From 8de5d9110054270815e50ae81339b01472b2e7ea Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 3 Mar 2013 19:56:30 -0500 Subject: [PATCH 0001/1224] Fixes #35: Solution file should be located in the root of the repository --- {src/.nuget => .nuget}/NuGet.Config | 0 {src/.nuget => .nuget}/NuGet.exe | Bin {src/.nuget => .nuget}/NuGet.targets | 0 src/Scriptcs.sln => ScriptCS.sln | 21 +++++++++++------- .../Scriptcs.Contracts.csproj | 4 ++-- src/Scriptcs/Scriptcs.csproj | 16 +++++++++++-- test/Scriptcs.Tests/Scriptcs.Tests.csproj | 12 +++++----- 7 files changed, 34 insertions(+), 19 deletions(-) rename {src/.nuget => .nuget}/NuGet.Config (100%) rename {src/.nuget => .nuget}/NuGet.exe (100%) rename {src/.nuget => .nuget}/NuGet.targets (100%) rename src/Scriptcs.sln => ScriptCS.sln (76%) diff --git a/src/.nuget/NuGet.Config b/.nuget/NuGet.Config similarity index 100% rename from src/.nuget/NuGet.Config rename to .nuget/NuGet.Config diff --git a/src/.nuget/NuGet.exe b/.nuget/NuGet.exe similarity index 100% rename from src/.nuget/NuGet.exe rename to .nuget/NuGet.exe diff --git a/src/.nuget/NuGet.targets b/.nuget/NuGet.targets similarity index 100% rename from src/.nuget/NuGet.targets rename to .nuget/NuGet.targets diff --git a/src/Scriptcs.sln b/ScriptCS.sln similarity index 76% rename from src/Scriptcs.sln rename to ScriptCS.sln index 8959db02..82311785 100644 --- a/src/Scriptcs.sln +++ b/ScriptCS.sln @@ -1,13 +1,15 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Contracts", "Scriptcs.Contracts\Scriptcs.Contracts.csproj", "{6049E205-8B5F-4080-B023-70600E51FD64}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs", "src\Scriptcs\Scriptcs.csproj", "{25080671-1A80-4041-B9C7-260578FF4849}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs", "Scriptcs\Scriptcs.csproj", "{25080671-1A80-4041-B9C7-260578FF4849}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Contracts", "src\Scriptcs.Contracts\Scriptcs.Contracts.csproj", "{6049E205-8B5F-4080-B023-70600E51FD64}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Tests", "../test/Scriptcs.Tests\Scriptcs.Tests.csproj", "{4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Tests", "test\Scriptcs.Tests\Scriptcs.Tests.csproj", "{4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2A511B15-662D-4F12-B63C-7D62BE01487B}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A59C6538-62EA-4BF6-AA00-E0E9A2892D47}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{E95E5426-BF99-458E-AE6F-544DBBA9BC9E}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config .nuget\NuGet.exe = .nuget\NuGet.exe @@ -20,14 +22,14 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6049E205-8B5F-4080-B023-70600E51FD64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6049E205-8B5F-4080-B023-70600E51FD64}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6049E205-8B5F-4080-B023-70600E51FD64}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6049E205-8B5F-4080-B023-70600E51FD64}.Release|Any CPU.Build.0 = Release|Any CPU {25080671-1A80-4041-B9C7-260578FF4849}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {25080671-1A80-4041-B9C7-260578FF4849}.Debug|Any CPU.Build.0 = Debug|Any CPU {25080671-1A80-4041-B9C7-260578FF4849}.Release|Any CPU.ActiveCfg = Release|Any CPU {25080671-1A80-4041-B9C7-260578FF4849}.Release|Any CPU.Build.0 = Release|Any CPU + {6049E205-8B5F-4080-B023-70600E51FD64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6049E205-8B5F-4080-B023-70600E51FD64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6049E205-8B5F-4080-B023-70600E51FD64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6049E205-8B5F-4080-B023-70600E51FD64}.Release|Any CPU.Build.0 = Release|Any CPU {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -36,4 +38,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} + EndGlobalSection EndGlobal diff --git a/src/Scriptcs.Contracts/Scriptcs.Contracts.csproj b/src/Scriptcs.Contracts/Scriptcs.Contracts.csproj index 9a0def9f..282a95bc 100644 --- a/src/Scriptcs.Contracts/Scriptcs.Contracts.csproj +++ b/src/Scriptcs.Contracts/Scriptcs.Contracts.csproj @@ -37,11 +37,11 @@ True - ..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll True - ..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll diff --git a/src/Scriptcs/Scriptcs.csproj b/src/Scriptcs/Scriptcs.csproj index 00802450..edcaa9f8 100644 --- a/src/Scriptcs/Scriptcs.csproj +++ b/src/Scriptcs/Scriptcs.csproj @@ -40,11 +40,23 @@ True - ..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll True - ..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + + + True + ..\..\packages\Roslyn.Services.Common.1.2.20906.2\lib\net45\Roslyn.Services.dll + + + True + ..\..\packages\Roslyn.Services.CSharp.1.2.20906.2\lib\net45\Roslyn.Services.CSharp.dll + + + True + ..\..\packages\Roslyn.Services.Common.1.2.20906.2\lib\net45\Roslyn.Utilities.dll diff --git a/test/Scriptcs.Tests/Scriptcs.Tests.csproj b/test/Scriptcs.Tests/Scriptcs.Tests.csproj index c9c7c667..1558e7d6 100644 --- a/test/Scriptcs.Tests/Scriptcs.Tests.csproj +++ b/test/Scriptcs.Tests/Scriptcs.Tests.csproj @@ -35,12 +35,11 @@ false - - False - ..\..\src\packages\Moq.4.0.10827\lib\NET40\Moq.dll + + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll - ..\..\src\packages\Should.1.1.12.0\lib\Should.dll + ..\..\packages\Should.1.1.12.0\lib\Should.dll @@ -49,9 +48,8 @@ - - False - ..\..\src\packages\xunit.1.9.1\lib\net20\xunit.dll + + ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll From cc9050cb707f2b666a4cac0873f00a0e9cd1dba1 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 3 Mar 2013 21:22:02 -0500 Subject: [PATCH 0002/1224] fix for #9 - support for #load to load dependent scripts --- src/Scriptcs/FilePreProcessor.cs | 78 +++++++++++ src/Scriptcs/FileSystem.cs | 15 +++ src/Scriptcs/IFilePreProcessor.cs | 10 ++ src/Scriptcs/IFileSystem.cs | 6 +- src/Scriptcs/ScriptExecutor.cs | 9 +- src/Scriptcs/Scriptcs.csproj | 2 + test/Scriptcs.Tests/FileProcessorTests.cs | 153 ++++++++++++++++++++++ test/Scriptcs.Tests/Scriptcs.Tests.csproj | 1 + 8 files changed, 270 insertions(+), 4 deletions(-) create mode 100644 src/Scriptcs/FilePreProcessor.cs create mode 100644 src/Scriptcs/IFilePreProcessor.cs create mode 100644 test/Scriptcs.Tests/FileProcessorTests.cs diff --git a/src/Scriptcs/FilePreProcessor.cs b/src/Scriptcs/FilePreProcessor.cs new file mode 100644 index 00000000..b1f0069c --- /dev/null +++ b/src/Scriptcs/FilePreProcessor.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Diagnostics; +using System.Linq; + +namespace Scriptcs +{ + public class FilePreProcessor : IFilePreProcessor + { + private const string LoadString = "#load "; + private const string UsingString = "using "; + + private readonly IFileSystem _fileSystem; + + [ImportingConstructor] + public FilePreProcessor(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + + public string ProcessFile(string path) + { + var entryFile = _fileSystem.ReadFileLines(path); + var parsed = ParseFile(entryFile); + + var result = string.Join(_fileSystem.NewLine, parsed.Item1); + result += _fileSystem.NewLine + parsed.Item2; + + return result; + } + + private Tuple, string> ParseFile(IEnumerable file) + { + var usings = new List(); + + var fileList = file.ToList(); + for (var i = 0; i < fileList.Count; i++) + { + var line = fileList[i]; + if (IsUsingLine(line)) + { + usings.Add(line); + } + + if (IsLoadLine(line)) + { + var filepath = line.Trim(' ').Replace(LoadString, "").Replace("\"", "").Replace(";",""); + var filecontent = _fileSystem.IsPathRooted(filepath) + ? _fileSystem.ReadFileLines(filepath) + : _fileSystem.ReadFileLines(_fileSystem.CurrentDirectory + @"\" + filepath); + + if (filecontent != null) + { + var parsed = ParseFile(filecontent); + fileList[i] = parsed.Item2; + usings.AddRange(parsed.Item1); + } + } + } + + var result = string.Join(_fileSystem.NewLine, fileList.Where(line => !IsUsingLine(line))); + var tuple = new Tuple, string>(usings.Distinct().ToList(), result); + + return tuple; + } + + private static bool IsUsingLine(string line) + { + return line.TrimStart(' ').StartsWith(UsingString) && !line.Contains("{") && line.Contains(";"); + } + + private static bool IsLoadLine(string line) + { + return line.TrimStart(' ').StartsWith(LoadString); + } + } +} \ No newline at end of file diff --git a/src/Scriptcs/FileSystem.cs b/src/Scriptcs/FileSystem.cs index a9f9afb7..7a8dd74a 100644 --- a/src/Scriptcs/FileSystem.cs +++ b/src/Scriptcs/FileSystem.cs @@ -34,11 +34,26 @@ public string ReadFile(string path) return File.ReadAllText(path); } + public string[] ReadFileLines(string path) + { + return File.ReadAllLines(path); + } + + public bool IsPathRooted(string path) + { + return Path.IsPathRooted(path); + } + public string CurrentDirectory { get { return Environment.CurrentDirectory; } } + public string NewLine + { + get { return Environment.NewLine; } + } + public DateTime GetLastWriteTime(string file) { return File.GetLastWriteTime(file); diff --git a/src/Scriptcs/IFilePreProcessor.cs b/src/Scriptcs/IFilePreProcessor.cs new file mode 100644 index 00000000..c93eac3e --- /dev/null +++ b/src/Scriptcs/IFilePreProcessor.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.Composition; + +namespace Scriptcs +{ + [InheritedExport] + public interface IFilePreProcessor + { + string ProcessFile(string path); + } +} \ No newline at end of file diff --git a/src/Scriptcs/IFileSystem.cs b/src/Scriptcs/IFileSystem.cs index c0a4272b..94cb509e 100644 --- a/src/Scriptcs/IFileSystem.cs +++ b/src/Scriptcs/IFileSystem.cs @@ -15,7 +15,11 @@ public interface IFileSystem bool DirectoryExists(string path); void CreateDirectory(string path); string ReadFile(string path); - string CurrentDirectory { get; } + string[] ReadFileLines(string path); DateTime GetLastWriteTime(string file); + bool IsPathRooted(string path); + + string CurrentDirectory { get; } + string NewLine { get; } } } diff --git a/src/Scriptcs/ScriptExecutor.cs b/src/Scriptcs/ScriptExecutor.cs index 07d690e0..c8ed9a89 100644 --- a/src/Scriptcs/ScriptExecutor.cs +++ b/src/Scriptcs/ScriptExecutor.cs @@ -13,11 +13,13 @@ namespace Scriptcs public class ScriptExecutor : IScriptExecutor { private readonly IFileSystem _fileSystem; + private readonly IFilePreProcessor _filePreProcessor; [ImportingConstructor] - public ScriptExecutor(IFileSystem fileSystem) + public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor) { _fileSystem = fileSystem; + _filePreProcessor = filePreProcessor; } public void Execute(string script, IEnumerable paths, IEnumerable recipes) @@ -41,9 +43,10 @@ public void Execute(string script, IEnumerable paths, IEnumerable + + diff --git a/test/Scriptcs.Tests/FileProcessorTests.cs b/test/Scriptcs.Tests/FileProcessorTests.cs new file mode 100644 index 00000000..7b50718c --- /dev/null +++ b/test/Scriptcs.Tests/FileProcessorTests.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Moq; +using Xunit; + +namespace Scriptcs.Tests +{ + public class FileProcessorTests + { + private List file1 = new List + { + "using System;", + @"Console.WriteLine(""Hello Script 1"");", + @"Console.WriteLine(""Loading Script 2"");", + @"#load ""script2.csx""", + @"Console.WriteLine(""Loaded Script 2"");", + @"Console.WriteLine(""Loading Script 4"");", + @"#load ""script4.csx"";", + @"Console.WriteLine(""Loaded Script 4"");", + @"Console.WriteLine(""Goodbye Script 1"");" + }; + + private List file2 = new List + { + "using System;", + @"Console.WriteLine(""Hello Script 2"");", + @"Console.WriteLine(""Loading Script 3"");", + @"#load ""script3.csx""", + @"Console.WriteLine(""Loaded Script 3"");", + @"Console.WriteLine(""Goodbye Script 2"");" + }; + + private List file3 = new List + { + "using System;", + "using System.Collections.Generic;", + @"Console.WriteLine(""Hello Script 3"");", + @"Console.WriteLine(""Goodbye Script 3"");" + }; + + private List file4 = new List + { + "using System;", + "using System.Core;", + @"Console.WriteLine(""Hello Script 4"");", + @"Console.WriteLine(""Goodbye Script 4"");" + }; + + private readonly Mock _fileSystem; + + public FileProcessorTests() + { + _fileSystem = new Mock(); + _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + .Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + .Returns(file2.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) + .Returns(file3.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + .Returns(file4.ToArray()); + } + + [Fact] + public void MultipleUsingStatementsShouldProduceDistinctOutput() + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))),Times.Exactly(4)); + Assert.Equal(3, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + } + + [Fact] + public void UsingStateMentsShoulAllBeAtTheTop() + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + + Assert.True(lastUsing < firsNotUsing); + } + + [Fact] + public void ThreeLoadedFilesShoulAllBeCalledOnce() + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + } + + [Fact] + public void LoadBeforeUsingShouldBeAllowed() + { + var file = new List + { + @"#load ""script4.csx""", + "", + "using System;", + @"Console.WriteLine(""abc"");" + }; + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); + + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + + Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + Assert.True(lastUsing < firsNotUsing); + } + + [Fact] + public void UsingInCodeDoesNotCountAsUsingImport() + { + var file = new List + { + @"#load ""script4.csx""", + "", + "using System;", + "using System.IO;", + "Console.WriteLine();", + @"using (var stream = new MemoryStream) {", + @"//do stuff", + @"}" + }; + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); + + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var firstNonImportUsing = splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); + var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); + + Assert.True(firstNonImportUsing > firstCodeLine); + } + } +} diff --git a/test/Scriptcs.Tests/Scriptcs.Tests.csproj b/test/Scriptcs.Tests/Scriptcs.Tests.csproj index 1558e7d6..7b0ac8a4 100644 --- a/test/Scriptcs.Tests/Scriptcs.Tests.csproj +++ b/test/Scriptcs.Tests/Scriptcs.Tests.csproj @@ -53,6 +53,7 @@ + From 4c294e0ace6158ba44900cac0dabe0b8d1c31751 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 3 Mar 2013 21:50:49 -0500 Subject: [PATCH 0003/1224] added #load sample --- samples/referencing-scripts/start.csx | 16 ++++++++++++++++ samples/referencing-scripts/utility.csx | 15 +++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 samples/referencing-scripts/start.csx create mode 100644 samples/referencing-scripts/utility.csx diff --git a/samples/referencing-scripts/start.csx b/samples/referencing-scripts/start.csx new file mode 100644 index 00000000..1c5447cd --- /dev/null +++ b/samples/referencing-scripts/start.csx @@ -0,0 +1,16 @@ +#load "utility.csx" + +using System; + +var time = PerformanceUtilities.ExecutionTime(() => +{ + var total = 0; + for (int i = 0; i < 10000; i++) + { + total += i; + Console.WriteLine("Iteration: {0}, Running total: {1}", i, total); + } +}); + +Console.WriteLine("Loop execution took: {0}", time); +Console.ReadKey(); \ No newline at end of file diff --git a/samples/referencing-scripts/utility.csx b/samples/referencing-scripts/utility.csx new file mode 100644 index 00000000..ae430ada --- /dev/null +++ b/samples/referencing-scripts/utility.csx @@ -0,0 +1,15 @@ +using System.Diagnostics; + +public class PerformanceUtilities +{ + public static long ExecutionTime(Action action) + { + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + action(); + + stopwatch.Stop(); + return stopwatch.ElapsedMilliseconds; + } +} \ No newline at end of file From 27b415a3e4fc01fcfb912e4d5e2d127a5607aac4 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 3 Mar 2013 20:34:25 -0500 Subject: [PATCH 0004/1224] Create Scriptcs.Core project --- ScriptCS.sln | 6 +++ src/Scriptcs.Core/Properties/AssemblyInfo.cs | 36 +++++++++++++ src/Scriptcs.Core/Scriptcs.Core.csproj | 55 ++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 src/Scriptcs.Core/Properties/AssemblyInfo.cs create mode 100644 src/Scriptcs.Core/Scriptcs.Core.csproj diff --git a/ScriptCS.sln b/ScriptCS.sln index 82311785..bbf8eeb5 100644 --- a/ScriptCS.sln +++ b/ScriptCS.sln @@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{E95E54 .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Core", "src\Scriptcs.Core\Scriptcs.Core.csproj", "{E590E710-E159-48E6-A3E6-1A83D3FE732C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -34,6 +36,10 @@ Global {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Release|Any CPU.Build.0 = Release|Any CPU + {E590E710-E159-48E6-A3E6-1A83D3FE732C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E590E710-E159-48E6-A3E6-1A83D3FE732C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E590E710-E159-48E6-A3E6-1A83D3FE732C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E590E710-E159-48E6-A3E6-1A83D3FE732C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Scriptcs.Core/Properties/AssemblyInfo.cs b/src/Scriptcs.Core/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..3df4438c --- /dev/null +++ b/src/Scriptcs.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Scriptcs.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Scriptcs.Core")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4c4ebd22-f4b0-47de-a417-f0a2a127508c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Scriptcs.Core/Scriptcs.Core.csproj b/src/Scriptcs.Core/Scriptcs.Core.csproj new file mode 100644 index 00000000..8a4e3365 --- /dev/null +++ b/src/Scriptcs.Core/Scriptcs.Core.csproj @@ -0,0 +1,55 @@ + + + + + Debug + AnyCPU + {E590E710-E159-48E6-A3E6-1A83D3FE732C} + Library + Properties + Scriptcs + Scriptcs.Core + v4.5 + 512 + ..\..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + \ No newline at end of file From 092b025efa32d3b1780e66fe4a06c4b2cbcc27b8 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 3 Mar 2013 20:34:44 -0500 Subject: [PATCH 0005/1224] Create Scriptcs.Core.Tests project --- ScriptCS.sln | 7 ++ .../Properties/AssemblyInfo.cs | 36 ++++++++++ .../Scriptcs.Core.Tests.csproj | 70 +++++++++++++++++++ test/Scriptcs.Core.Tests/packages.config | 5 ++ 4 files changed, 118 insertions(+) create mode 100644 test/Scriptcs.Core.Tests/Properties/AssemblyInfo.cs create mode 100644 test/Scriptcs.Core.Tests/Scriptcs.Core.Tests.csproj create mode 100644 test/Scriptcs.Core.Tests/packages.config diff --git a/ScriptCS.sln b/ScriptCS.sln index bbf8eeb5..fab92b4b 100644 --- a/ScriptCS.sln +++ b/ScriptCS.sln @@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{E95E54 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Core", "src\Scriptcs.Core\Scriptcs.Core.csproj", "{E590E710-E159-48E6-A3E6-1A83D3FE732C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Core.Tests", "test\Scriptcs.Core.Tests\Scriptcs.Core.Tests.csproj", "{AC228213-7356-4F0D-BA48-EBA5FB8A7506}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -40,11 +42,16 @@ Global {E590E710-E159-48E6-A3E6-1A83D3FE732C}.Debug|Any CPU.Build.0 = Debug|Any CPU {E590E710-E159-48E6-A3E6-1A83D3FE732C}.Release|Any CPU.ActiveCfg = Release|Any CPU {E590E710-E159-48E6-A3E6-1A83D3FE732C}.Release|Any CPU.Build.0 = Release|Any CPU + {AC228213-7356-4F0D-BA48-EBA5FB8A7506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC228213-7356-4F0D-BA48-EBA5FB8A7506}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC228213-7356-4F0D-BA48-EBA5FB8A7506}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC228213-7356-4F0D-BA48-EBA5FB8A7506}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} + {AC228213-7356-4F0D-BA48-EBA5FB8A7506} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} EndGlobalSection EndGlobal diff --git a/test/Scriptcs.Core.Tests/Properties/AssemblyInfo.cs b/test/Scriptcs.Core.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..64cd7c90 --- /dev/null +++ b/test/Scriptcs.Core.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Scriptcs.Core.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Scriptcs.Core.Tests")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fe718b7f-5fb4-43eb-a3da-26a1d25e644c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/Scriptcs.Core.Tests/Scriptcs.Core.Tests.csproj b/test/Scriptcs.Core.Tests/Scriptcs.Core.Tests.csproj new file mode 100644 index 00000000..e01a71ac --- /dev/null +++ b/test/Scriptcs.Core.Tests/Scriptcs.Core.Tests.csproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + {AC228213-7356-4F0D-BA48-EBA5FB8A7506} + Library + Properties + Scriptcs + Scriptcs.Core.Tests + v4.5 + 512 + ..\..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll + + + + + + + + + + ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + + + + + + + {e590e710-e159-48e6-a3e6-1a83d3fe732c} + Scriptcs.Core + + + + + + + + + \ No newline at end of file diff --git a/test/Scriptcs.Core.Tests/packages.config b/test/Scriptcs.Core.Tests/packages.config new file mode 100644 index 00000000..f6267914 --- /dev/null +++ b/test/Scriptcs.Core.Tests/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 54b2b6cb7a2ccc3d66fd0df3adc634c3c37efa6a Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 3 Mar 2013 20:35:59 -0500 Subject: [PATCH 0006/1224] Scriptcs.Core should reference the Roslyn Compiler assemblies --- src/Scriptcs.Core/Scriptcs.Core.csproj | 11 +++++++++++ src/Scriptcs.Core/packages.config | 5 +++++ 2 files changed, 16 insertions(+) create mode 100644 src/Scriptcs.Core/packages.config diff --git a/src/Scriptcs.Core/Scriptcs.Core.csproj b/src/Scriptcs.Core/Scriptcs.Core.csproj index 8a4e3365..a7a96bcb 100644 --- a/src/Scriptcs.Core/Scriptcs.Core.csproj +++ b/src/Scriptcs.Core/Scriptcs.Core.csproj @@ -32,6 +32,14 @@ 4 + + True + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + + + True + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + @@ -43,6 +51,9 @@ + + + + \ No newline at end of file diff --git a/spikes/DebugSymbols/DebugSymbols/Program.cs b/spikes/DebugSymbols/DebugSymbols/Program.cs new file mode 100644 index 00000000..52660533 --- /dev/null +++ b/spikes/DebugSymbols/DebugSymbols/Program.cs @@ -0,0 +1,64 @@ +using Roslyn.Compilers; +using Roslyn.Compilers.CSharp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DebugSymbols +{ + class Program + { + static void Main(string[] args) + { + var filePath = args[0]; + var fileDir = Path.GetDirectoryName(filePath); + fileDir = Path.IsPathRooted(filePath) ? fileDir : Path.Combine(Environment.CurrentDirectory, fileDir); + var fileName = Path.GetFileName(filePath); + var nameWithoutExtension = fileName.Replace(Path.GetExtension(fileName), string.Empty); + var outputName = nameWithoutExtension + ".exe"; + var outputPath = Path.Combine(fileDir, outputName); + var pdbPath = Path.Combine(fileDir, nameWithoutExtension + ".pdb"); + + var code = File.ReadAllText(filePath); + + var tree = SyntaxTree.ParseText(code); + + var compilation = Compilation.Create("DerivedClass") + .WithOptions(new CompilationOptions(OutputKind.ConsoleApplication)) + .AddSyntaxTrees(tree) + .AddReferences( + MetadataReference.CreateAssemblyReference("mscorlib"), + MetadataReference.CreateAssemblyReference("System"), + MetadataReference.CreateAssemblyReference("System.Core")); + + // need to add assemblies + EmitResult result; + + using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate)) + using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate)) + { + result = compilation.Emit(outputStream, outputName, pdbPath, pdbStream); + } + + if (result.Success) + { + Console.WriteLine("Compilation successful"); + Console.WriteLine(string.Format("Output .exe at {0}", outputPath)); + Console.WriteLine(string.Format("Output .pdb at {0}", pdbPath)); + } + else + { + Console.WriteLine("Compilation failed"); + foreach (var error in result.Diagnostics) + { + Console.WriteLine(error); + } + } + + Console.ReadKey(); + } + } +} \ No newline at end of file diff --git a/spikes/DebugSymbols/DebugSymbols/Properties/AssemblyInfo.cs b/spikes/DebugSymbols/DebugSymbols/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..0c85c0fc --- /dev/null +++ b/spikes/DebugSymbols/DebugSymbols/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DebugSymbols")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DebugSymbols")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("47c9e190-3721-40db-bb50-f4b39ca26510")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] From e52d1b334bf39f19dc86bfaa362502c11cb9c06e Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 7 Mar 2013 21:30:59 -0500 Subject: [PATCH 0035/1224] merge conflicts --- src/ScriptCs.Contracts/IScriptPack.cs | 17 +++ ...ecipeMetadata.cs => IScriptPackContext.cs} | 3 +- src/ScriptCs.Contracts/IScriptsRecipe.cs | 13 -- src/ScriptCs.Contracts/ISession.cs | 8 ++ .../ScriptCs.Contracts.csproj | 6 +- src/ScriptCs.Contracts/ScriptcsRecipe.cs | 23 ---- src/ScriptCs.Core/IRecipeManager.cs | 10 -- src/ScriptCs.Core/IScriptEngine.cs | 1 + src/ScriptCs.Core/IScriptExecutor.cs | 2 +- src/ScriptCs.Core/IScriptHostFactory.cs | 16 +++ src/ScriptCs.Core/IScriptPackResolver.cs | 10 ++ src/ScriptCs.Core/ISession.cs | 7 -- src/ScriptCs.Core/RecipeManager.cs | 34 ------ src/ScriptCs.Core/ScriptCs.Core.csproj | 9 +- src/ScriptCs.Core/ScriptExecutor.cs | 58 +++++++-- src/ScriptCs.Core/ScriptHost.cs | 18 +++ src/ScriptCs.Core/ScriptHostFactory.cs | 13 ++ src/ScriptCs.Core/ScriptPackManager.cs | 24 ++++ src/ScriptCs.Core/ScriptPackResolver.cs | 28 +++++ .../Wrappers/ScriptEngineWrapper.cs | 1 + src/ScriptCs.Core/Wrappers/SessionWrapper.cs | 12 +- src/ScriptCs/Program.cs | 24 +--- .../ScriptCs.Core.Tests.csproj | 2 + .../ScriptExecutorTests.cs | 112 +++++++++++++++--- .../ScriptPackResolverTests.cs | 61 ++++++++++ 25 files changed, 371 insertions(+), 141 deletions(-) create mode 100644 src/ScriptCs.Contracts/IScriptPack.cs rename src/ScriptCs.Contracts/{IScriptcsRecipeMetadata.cs => IScriptPackContext.cs} (69%) delete mode 100644 src/ScriptCs.Contracts/IScriptsRecipe.cs create mode 100644 src/ScriptCs.Contracts/ISession.cs delete mode 100644 src/ScriptCs.Contracts/ScriptcsRecipe.cs delete mode 100644 src/ScriptCs.Core/IRecipeManager.cs create mode 100644 src/ScriptCs.Core/IScriptHostFactory.cs create mode 100644 src/ScriptCs.Core/IScriptPackResolver.cs delete mode 100644 src/ScriptCs.Core/ISession.cs delete mode 100644 src/ScriptCs.Core/RecipeManager.cs create mode 100644 src/ScriptCs.Core/ScriptHost.cs create mode 100644 src/ScriptCs.Core/ScriptHostFactory.cs create mode 100644 src/ScriptCs.Core/ScriptPackManager.cs create mode 100644 src/ScriptCs.Core/ScriptPackResolver.cs create mode 100644 test/ScriptCs.Core.Tests/ScriptPackResolverTests.cs diff --git a/src/ScriptCs.Contracts/IScriptPack.cs b/src/ScriptCs.Contracts/IScriptPack.cs new file mode 100644 index 00000000..06c29bf8 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptPack.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Text; +using Roslyn.Scripting.CSharp; + +namespace ScriptCs.Contracts +{ + [InheritedExport] + public interface IScriptPack + { + void Initialize(ISession session); + IScriptPackContext GetContext(); + void Terminate(); + } +} diff --git a/src/ScriptCs.Contracts/IScriptcsRecipeMetadata.cs b/src/ScriptCs.Contracts/IScriptPackContext.cs similarity index 69% rename from src/ScriptCs.Contracts/IScriptcsRecipeMetadata.cs rename to src/ScriptCs.Contracts/IScriptPackContext.cs index 927cded7..2e35f69c 100644 --- a/src/ScriptCs.Contracts/IScriptcsRecipeMetadata.cs +++ b/src/ScriptCs.Contracts/IScriptPackContext.cs @@ -6,8 +6,7 @@ namespace ScriptCs.Contracts { - public interface IScriptCsRecipeMetadata + public interface IScriptPackContext { - string Name { get; } } } diff --git a/src/ScriptCs.Contracts/IScriptsRecipe.cs b/src/ScriptCs.Contracts/IScriptsRecipe.cs deleted file mode 100644 index c3ab22e6..00000000 --- a/src/ScriptCs.Contracts/IScriptsRecipe.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Roslyn.Scripting.CSharp; - -namespace ScriptCs.Contracts -{ - public interface IScriptCsRecipe - { - void ConfigureEngine(ScriptEngine engine); - } -} diff --git a/src/ScriptCs.Contracts/ISession.cs b/src/ScriptCs.Contracts/ISession.cs new file mode 100644 index 00000000..e87d1610 --- /dev/null +++ b/src/ScriptCs.Contracts/ISession.cs @@ -0,0 +1,8 @@ +namespace ScriptCs.Contracts +{ + public interface ISession + { + object Execute(string code); + void AddReference(string assemblyDisplayNameOrPath); + } +} diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 75985eef..8e11be08 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -53,10 +53,10 @@ - - + + + - diff --git a/src/ScriptCs.Contracts/ScriptcsRecipe.cs b/src/ScriptCs.Contracts/ScriptcsRecipe.cs deleted file mode 100644 index 90fde789..00000000 --- a/src/ScriptCs.Contracts/ScriptcsRecipe.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - [Export(typeof (IScriptCsRecipe))] - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - [MetadataAttribute] - public class ScriptCsRecipe : ExportAttribute, IScriptCsRecipeMetadata - { - public ScriptCsRecipe(string name) - { - Name = name; - } - - public string Name { get; private set; } - } - -} diff --git a/src/ScriptCs.Core/IRecipeManager.cs b/src/ScriptCs.Core/IRecipeManager.cs deleted file mode 100644 index 044d43e0..00000000 --- a/src/ScriptCs.Core/IRecipeManager.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ScriptCs.Contracts; -using System.Collections.Generic; - -namespace ScriptCs -{ - public interface IRecipeManager - { - IEnumerable GetReceipes(IEnumerable recipeNames); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index e5a2b00e..df07b55b 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -2,6 +2,7 @@ using System.ComponentModel.Composition; using Roslyn.Scripting; +using ScriptCs.Contracts; namespace ScriptCs { diff --git a/src/ScriptCs.Core/IScriptExecutor.cs b/src/ScriptCs.Core/IScriptExecutor.cs index 57e5463e..5b455302 100644 --- a/src/ScriptCs.Core/IScriptExecutor.cs +++ b/src/ScriptCs.Core/IScriptExecutor.cs @@ -7,6 +7,6 @@ namespace ScriptCs [InheritedExport] public interface IScriptExecutor { - void Execute(string script, IEnumerable paths, IEnumerable recipes); + void Execute(string script, IEnumerable paths, IEnumerable recipes); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptHostFactory.cs b/src/ScriptCs.Core/IScriptHostFactory.cs new file mode 100644 index 00000000..63c0787c --- /dev/null +++ b/src/ScriptCs.Core/IScriptHostFactory.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + [InheritedExport] + public interface IScriptHostFactory + { + ScriptHost CreateScriptHost(IEnumerable contexts); + } +} diff --git a/src/ScriptCs.Core/IScriptPackResolver.cs b/src/ScriptCs.Core/IScriptPackResolver.cs new file mode 100644 index 00000000..7dff0cf6 --- /dev/null +++ b/src/ScriptCs.Core/IScriptPackResolver.cs @@ -0,0 +1,10 @@ +using ScriptCs.Contracts; +using System.Collections.Generic; + +namespace ScriptCs +{ + public interface IScriptPackResolver + { + IEnumerable GetPacks(); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ISession.cs b/src/ScriptCs.Core/ISession.cs deleted file mode 100644 index 32c36250..00000000 --- a/src/ScriptCs.Core/ISession.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ScriptCs -{ - public interface ISession - { - object Execute(string code); - } -} diff --git a/src/ScriptCs.Core/RecipeManager.cs b/src/ScriptCs.Core/RecipeManager.cs deleted file mode 100644 index 6b8706fc..00000000 --- a/src/ScriptCs.Core/RecipeManager.cs +++ /dev/null @@ -1,34 +0,0 @@ -using ScriptCs.Contracts; -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition.Hosting; -using System.Linq; - -namespace ScriptCs -{ - public class RecipeManager : IRecipeManager - { - private readonly CompositionContainer _container; - - public RecipeManager(CompositionContainer container) - { - _container = container; - } - - public IEnumerable GetReceipes(IEnumerable recipeNames) - { - var recipes = new List(); - - foreach (var recipeName in recipeNames) - { - var name = recipeName; - var recipeExports = _container.GetExportedValues>() - .Where(l => name == l.Metadata.Name); - - recipes.AddRange(recipeExports.Select(re => re.Value)); - } - - return recipes; - } - } -} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 49fb90c2..da9ab359 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -60,10 +60,10 @@ - + + - @@ -73,7 +73,10 @@ - + + + + diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index bb6d7f9b..50e28811 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -12,16 +12,24 @@ public class ScriptExecutor : IScriptExecutor private readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; private readonly IScriptEngine _scriptEngine; + private readonly IScriptHostFactory _scriptHostFactory; [ImportingConstructor] - public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) + public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) { _fileSystem = fileSystem; _filePreProcessor = filePreProcessor; _scriptEngine = scriptEngine; + _scriptHostFactory = scriptHostFactory; } - public void Execute(string script, IEnumerable paths, IEnumerable recipes) + public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) : + this(fileSystem, filePreProcessor, scriptEngine, new ScriptHostFactory()) + { + + } + + public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) { _scriptEngine.AddReference("System"); _scriptEngine.AddReference("System.Core"); @@ -30,6 +38,21 @@ public void Execute(string script, IEnumerable paths, IEnumerable PrepareBinFolder(IEnumerable paths, string bin) + { + var files = new List(); + if (!_fileSystem.DirectoryExists(bin)) _fileSystem.CreateDirectory(bin); @@ -40,14 +63,35 @@ public void Execute(string script, IEnumerable paths, IEnumerable files, ISession session) + { + foreach (var file in files) + { + session.AddReference(file); + } + } - _scriptEngine.AddReference(destFile); + private IEnumerable GetContexts(IEnumerable scriptPacks) + { + foreach (var pack in scriptPacks) + { + yield return pack.GetContext(); } + } - var session = _scriptEngine.CreateSession(); - var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); - var csx = _filePreProcessor.ProcessFile(path); - session.Execute(csx); + private void InitializeScriptPacks(IEnumerable scriptPacks, ISession session) + { + foreach (var pack in scriptPacks) + { + pack.Initialize(session); + } } + } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptHost.cs b/src/ScriptCs.Core/ScriptHost.cs new file mode 100644 index 00000000..2c6efcba --- /dev/null +++ b/src/ScriptCs.Core/ScriptHost.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public class ScriptHost + { + public ScriptHost(IEnumerable contexts) + { + ScriptPackManager = new ScriptPackManager(contexts); + } + + public ScriptPackManager ScriptPackManager { get; private set; } + } +} diff --git a/src/ScriptCs.Core/ScriptHostFactory.cs b/src/ScriptCs.Core/ScriptHostFactory.cs new file mode 100644 index 00000000..76988199 --- /dev/null +++ b/src/ScriptCs.Core/ScriptHostFactory.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public class ScriptHostFactory : IScriptHostFactory + { + public ScriptHost CreateScriptHost(IEnumerable contexts) + { + return new ScriptHost(contexts); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptPackManager.cs b/src/ScriptCs.Core/ScriptPackManager.cs new file mode 100644 index 00000000..4d03d723 --- /dev/null +++ b/src/ScriptCs.Core/ScriptPackManager.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public class ScriptPackManager + { + private IDictionary _contexts = new Dictionary(); + + public ScriptPackManager(IEnumerable contexts) + { + foreach (var context in contexts) + { + _contexts.Add(context.GetType(), context); + } + } + + public TContext Get() where TContext : IScriptPackContext + { + return (TContext) _contexts[typeof (TContext)]; + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptPackResolver.cs b/src/ScriptCs.Core/ScriptPackResolver.cs new file mode 100644 index 00000000..e33fa5c3 --- /dev/null +++ b/src/ScriptCs.Core/ScriptPackResolver.cs @@ -0,0 +1,28 @@ +using ScriptCs.Contracts; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Linq; + +namespace ScriptCs +{ + public class ScriptPackResolver : IScriptPackResolver + { + private readonly ExportProvider _exportProvider; + private IEnumerable _scriptPacks; + + public ScriptPackResolver(ExportProvider exportProvider) + { + _exportProvider = exportProvider; + } + + public IEnumerable GetPacks() + { + if (_scriptPacks == null) + { + _scriptPacks = _exportProvider.GetExportedValues(); + } + return _scriptPacks; + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs index e928c8e9..e8c76214 100644 --- a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs @@ -1,5 +1,6 @@ using Roslyn.Scripting; using Roslyn.Scripting.CSharp; +using ScriptCs.Contracts; namespace ScriptCs.Wrappers { diff --git a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs index 946abc5a..e1a8306e 100644 --- a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs @@ -1,19 +1,25 @@ using Roslyn.Scripting; +using ScriptCs.Contracts; namespace ScriptCs.Wrappers { public class SessionWrapper : ISession { - private Session session; + private Session _session; public SessionWrapper(Session session) { - this.session = session; + this._session = session; } public object Execute(string code) { - return this.session.Execute(code); + return this._session.Execute(code); + } + + public void AddReference(string assemblyDisplayNameOrPath) + { + this._session.AddReference(assemblyDisplayNameOrPath); } } } diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 3d2b7395..ff712004 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -14,28 +14,20 @@ private static void Main(string[] args) { if (args.Length == 0) { - Console.WriteLine("Usage:\r\n\r\nscriptcs [file] [recipe1] [recipe2] ...\r\n"); + Console.WriteLine("Usage:\r\n\r\nscriptcs [file]\r\n"); return; } var script = args[0]; - var recipes = new List(); - if (args.Length > 1) - { - for (int i = 1; i <= args.Length; i++) - { - recipes.Add(args[i]); - } - } - var container = ConfigureMef(); var fileSystem = container.GetExportedValue(); var packageContainer = container.GetExportedValue(); var resolver = container.GetExportedValue(); + var executor = container.GetExportedValue(); - var recipeManager = new RecipeManager(container); + var scriptPackManager = new ScriptPackResolver(container); try { @@ -45,7 +37,7 @@ private static void Main(string[] args) { Console.WriteLine("Found assembly reference: " + path); } - executor.Execute(script, paths, recipeManager.GetReceipes(recipes)); + executor.Execute(script, paths, scriptPackManager.GetPacks()); } catch (MissingAssemblyException ex) { @@ -57,14 +49,8 @@ private static CompositionContainer ConfigureMef() { var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly)); - catalog.Catalogs.Add(new AssemblyCatalog(typeof(ScriptExecutor).Assembly)); - - var recipesFolder = AppDomain.CurrentDomain.BaseDirectory + @"\Recipes"; - if (!Directory.Exists(recipesFolder)) - Directory.CreateDirectory(recipesFolder); - - catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory + @"\Recipes")); + catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory,"*.pack.dll")); return new CompositionContainer(catalog); } } diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 97184a53..d58e57df 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -43,6 +43,7 @@ ..\..\packages\Should.1.1.12.0\lib\Should.dll + @@ -58,6 +59,7 @@ + diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index d4ec2690..927c4d77 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -9,13 +9,14 @@ namespace ScriptCs.Tests { - // had to update this class as unit tests did not follow approach requested in contrib (phil hack like tests) + // had to update this class as unit tests did not follow approach requested in contrib (phil hack lipowerke tests) public class ScriptExecutorTests { private static ScriptExecutor CreateScriptExecutor( Mock fileSystem = null, Mock fileProcessor = null, - Mock scriptEngine = null) + Mock scriptEngine = null, + Mock scriptHostFactory = null) { fileSystem = fileSystem ?? new Mock(); @@ -23,11 +24,24 @@ private static ScriptExecutor CreateScriptExecutor( if (scriptEngine == null) { + var mockSession = new Mock(); + mockSession.Setup(s => s.AddReference(It.IsAny())); + mockSession.Setup(s => s.Execute(It.IsAny())).Returns(new object()); + scriptEngine = new Mock(); - scriptEngine.Setup(e => e.CreateSession()).Returns(new Mock().Object); - } - - return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); + scriptEngine.SetupProperty(e => e.BaseDirectory); + scriptEngine.Setup(e => e.CreateSession()).Returns(mockSession.Object); + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(mockSession.Object); + } + + if (scriptHostFactory == null) + { + return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); + } + else + { + return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, scriptHostFactory.Object); + } } public class TheExecuteMethod @@ -44,7 +58,7 @@ public void ConstructsAbsolutePathBeforePreProcessingFile() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -59,7 +73,7 @@ public void DoNotChangePathIfAbsolute() preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -74,7 +88,7 @@ public void ShouldAddSystemAndSystemCoreReferencesToEngine() scriptEngine.Setup(e => e.AddReference("System")).Verifiable(); scriptEngine.Setup(e => e.AddReference("System.Core")).Verifiable(); - scriptEngine.Setup(e => e.CreateSession()).Returns(session.Object); + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); @@ -84,7 +98,7 @@ public void ShouldAddSystemAndSystemCoreReferencesToEngine() var scriptName = "script.csx"; var paths = new string[0]; - IEnumerable recipes = null; + IEnumerable recipes = Enumerable.Empty(); // act scriptExecutor.Execute(scriptName, paths, recipes); @@ -101,7 +115,7 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() var scriptEngine = new Mock(); var fileSystem = new Mock(); var session = new Mock(); - scriptEngine.Setup(e => e.CreateSession()).Returns(session.Object); + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); @@ -113,7 +127,7 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() var scriptName = "script.csx"; var paths = new string[0]; - IEnumerable recipes = null; + IEnumerable recipes = Enumerable.Empty(); // act scriptExecutor.Execute(scriptName, paths, recipes); @@ -131,7 +145,7 @@ public void ShouldCreateCurrentDirectoryIfItDoesNotExist() var fileSystem = new Mock(); var session = new Mock(); - scriptEngine.Setup(e => e.CreateSession()).Returns(session.Object); + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); @@ -146,7 +160,7 @@ public void ShouldCreateCurrentDirectoryIfItDoesNotExist() var scriptName = "script.csx"; var paths = new string[0]; - IEnumerable recipes = null; + IEnumerable recipes = Enumerable.Empty(); // act scriptExecutor.Execute(scriptName, paths, recipes); @@ -167,7 +181,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInSessionWhenExecuteIsIn string code = Guid.NewGuid().ToString(); - scriptEngine.Setup(e => e.CreateSession()).Returns(session.Object); + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); session.Setup(s => s.Execute(code)).Returns(null).Verifiable(); @@ -182,7 +196,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInSessionWhenExecuteIsIn var scriptName = "script.csx"; var paths = new string[0]; - IEnumerable recipes = null; + IEnumerable recipes = Enumerable.Empty(); preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(code).Verifiable(); @@ -193,6 +207,72 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInSessionWhenExecuteIsIn preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); session.Verify(s => s.Execute(code), Times.Once()); } + + [Fact] + public void ShouldInitializeScriptPacks() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); + + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + // var scriptPack2 = new Mock(); + // scriptPack2.Setup(p => p.Initialize(It.IsAny())); + + executor.Execute("script.csx", Enumerable.Empty(), new List { scriptPack1.Object }); + scriptPack1.Verify(p => p.Initialize(It.IsAny())); + // scriptPack2.Verify(p => p.Initialize(It.IsAny())); + } + + [Fact] + public void ShouldCreateScriptHostWithContexts() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny>())).Returns((IEnumerable c) => new ScriptHost(c)); + + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptHostFactory: scriptHostFactory); + + var scriptPack = new Mock(); + var context = new Mock().Object; + + scriptPack.Setup(p => p.GetContext()).Returns(context); + + executor.Execute("script.csx", Enumerable.Empty(), new List { scriptPack.Object }); + scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); + } + + [Fact] + public void ShouldCreateSessionWithScriptHost() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var engine = new Mock(); + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); + + engine.Setup(e => e.CreateSession(It.IsAny())).Returns(new Mock().Object); + executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + engine.Verify(e=>e.CreateSession(It.IsAny())); + } + } } } \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptPackResolverTests.cs b/test/ScriptCs.Core.Tests/ScriptPackResolverTests.cs new file mode 100644 index 00000000..c2068f28 --- /dev/null +++ b/test/ScriptCs.Core.Tests/ScriptPackResolverTests.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Moq.Protected; +using ScriptCs.Contracts; +using Xunit; +using Should; +using System.ComponentModel.Composition.Hosting; +using Moq; + +namespace ScriptCs.Tests +{ + public class ScriptPackResolverTests + { + public class TheGetPacksMethod + { + private ScriptPackResolver _packManager; + private TestExportProvider _exportProvider; + private Mock _pack1; + private Mock _pack2; + + public TheGetPacksMethod() + { + _pack1 = new Mock(); + _pack2 = new Mock(); + _exportProvider = new TestExportProvider(_pack1.Object, _pack2.Object); + _packManager = new ScriptPackResolver(_exportProvider); + } + + [Fact] + public void ShouldRetrieveAnyPacksInTheCatalog() + { + var packs = _packManager.GetPacks(); + packs.Count().ShouldEqual(2); + packs.ShouldContain(_pack1.Object); + packs.ShouldContain(_pack2.Object); + } + + } + + public class TestExportProvider : ExportProvider + { + private readonly IScriptPack[] _packs; + + public TestExportProvider(params IScriptPack[] packs) + { + _packs = packs; + } + + protected override IEnumerable GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) + { + return _packs.Select(p => new Export(AttributedModelServices.GetContractName(typeof(IScriptPack)), ()=>p)); + } + } + } +} From d0611750696047dcd26164c42c85b1f6953f280f Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Fri, 8 Mar 2013 01:08:49 -0300 Subject: [PATCH 0036/1224] # Added initial readme.md for spike, test.csx file and updated Program.cs --- spikes/DebugSymbols/DebugSymbols/Program.cs | 18 +++++- spikes/DebugSymbols/debugSession.png | Bin 0 -> 68972 bytes spikes/DebugSymbols/readme.md | 60 ++++++++++++++++++++ spikes/DebugSymbols/test.csx | 16 ++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 spikes/DebugSymbols/debugSession.png create mode 100644 spikes/DebugSymbols/readme.md create mode 100644 spikes/DebugSymbols/test.csx diff --git a/spikes/DebugSymbols/DebugSymbols/Program.cs b/spikes/DebugSymbols/DebugSymbols/Program.cs index 52660533..329da4e3 100644 --- a/spikes/DebugSymbols/DebugSymbols/Program.cs +++ b/spikes/DebugSymbols/DebugSymbols/Program.cs @@ -1,4 +1,5 @@ using Roslyn.Compilers; +using Roslyn.Compilers.Common; using Roslyn.Compilers.CSharp; using System; using System.Collections.Generic; @@ -13,6 +14,19 @@ class Program { static void Main(string[] args) { + if (args.Length == 0) + { + Console.WriteLine("Usage:\r\n\r\nDebugSymbols [.csx file] \r\n"); + Console.ReadKey(); + return; + } + + Console.WriteLine("IMPORTANT"); + Console.WriteLine("================================================"); + Console.WriteLine("In this spike the .csx file must only make use of classes in mscorlib, System and System.Core assemblies."); + Console.WriteLine("================================================"); + Console.WriteLine(); + var filePath = args[0]; var fileDir = Path.GetDirectoryName(filePath); fileDir = Path.IsPathRooted(filePath) ? fileDir : Path.Combine(Environment.CurrentDirectory, fileDir); @@ -27,7 +41,9 @@ static void Main(string[] args) var tree = SyntaxTree.ParseText(code); var compilation = Compilation.Create("DerivedClass") - .WithOptions(new CompilationOptions(OutputKind.ConsoleApplication)) + .WithOptions(new CompilationOptions(OutputKind.ConsoleApplication, + debugInformationKind: DebugInformationKind.Full, + platform: Platform.AnyCPU)) .AddSyntaxTrees(tree) .AddReferences( MetadataReference.CreateAssemblyReference("mscorlib"), diff --git a/spikes/DebugSymbols/debugSession.png b/spikes/DebugSymbols/debugSession.png new file mode 100644 index 0000000000000000000000000000000000000000..8bab89f553dd56eb4351ba67a703ce3be2329158 GIT binary patch literal 68972 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 z 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 Date: Fri, 8 Mar 2013 01:10:00 -0300 Subject: [PATCH 0037/1224] # Updated FilePreProcessor.cs to use Path.Combine instead of + string concat --- src/ScriptCs.Core/FilePreProcessor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 43c1fa56..92689fd0 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.Diagnostics; +using System.IO; using System.Linq; namespace ScriptCs @@ -45,10 +46,10 @@ private Tuple, string> ParseFile(IEnumerable file) if (IsLoadLine(line)) { - var filepath = line.Trim(' ').Replace(LoadString, "").Replace("\"", "").Replace(";",""); + var filepath = line.Trim(' ').Replace(LoadString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); var filecontent = _fileSystem.IsPathRooted(filepath) ? _fileSystem.ReadFileLines(filepath) - : _fileSystem.ReadFileLines(_fileSystem.CurrentDirectory + @"\" + filepath); + : _fileSystem.ReadFileLines(Path.Combine(_fileSystem.CurrentDirectory, filepath)); if (filecontent != null) { From 62fbc120a3744c993fb075844fb0d190524de72c Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Fri, 8 Mar 2013 01:16:57 -0300 Subject: [PATCH 0038/1224] Update readme.md --- spikes/DebugSymbols/readme.md | 38 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/spikes/DebugSymbols/readme.md b/spikes/DebugSymbols/readme.md index 99a518b4..6854f0af 100644 --- a/spikes/DebugSymbols/readme.md +++ b/spikes/DebugSymbols/readme.md @@ -10,7 +10,9 @@ DebugSymbols [.csx file] Findings ======== To compile SyntaxTree is being used, could not find a way to build from ScriptEngine. Generating a .pdb file with the current settings seems simple. The following figure shows a debugging session with mdbg (still need to figure out how to get mdbg to recognize the source file). -![alt text](image source url "Debugging session") +![alt text][logo] + +[logo]: https://github.com/dschenkelman/scriptcs/blob/dev/spikes/DebugSymbols/debugSession.png "Debugging session" Source needs to be a valid "compilation unit". In the case of a console app, that means having an entry point (main method) and inside a class. For example, this code: ``` @@ -24,22 +26,22 @@ Console.WriteLine(c); Console.ReadLine(); ``` Throws the following: - (4,9): error CS0116: A namespace does not directly contain members such as fields or methods - (5,9): error CS0116: A namespace does not directly contain members such as fields or methods - (4,18): error CS1022: Type or namespace definition, or end-of-file expected - (5,17): error CS1022: Type or namespace definition, or end-of-file expected - (11,9): error CS0116: A namespace does not directly contain members such as fields or methods - (11,18): error CS1022: Type or namespace definition, or end-of-file expected - (11,19): error CS0116: A namespace does not directly contain members such as fields or methods - (11,20): error CS1022: Type or namespace definition, or end-of-file expected - (12,9): error CS0116: A namespace does not directly contain members such as fields or methods - (12,17): error CS1022: Type or namespace definition, or end-of-file expected - (7,5): error CS0116: A namespace does not directly contain members such as fields or methods - (8,5): error CS0116: A namespace does not directly contain members such as fields or methods - (10,5): error CS0116: A namespace does not directly contain members such as fields or methods - (10,9): error CS0103: The name 'a' does not exist in the current context - (10,13): error CS0103: The name 'b' does not exist in the current context - error CS5001: Program does not contain a static 'Main' method suitable for an entry point +* (4,9): error CS0116: A namespace does not directly contain members such as fields or methods +* (5,9): error CS0116: A namespace does not directly contain members such as fields or methods +* (4,18): error CS1022: Type or namespace definition, or end-of-file expected +* (5,17): error CS1022: Type or namespace definition, or end-of-file expected +* (11,9): error CS0116: A namespace does not directly contain members such as fields or methods +* (11,18): error CS1022: Type or namespace definition, or end-of-file expected +* (11,19): error CS0116: A namespace does not directly contain members such as fields or methods +* (11,20): error CS1022: Type or namespace definition, or end-of-file expected +* (12,9): error CS0116: A namespace does not directly contain members such as fields or methods +* (12,17): error CS1022: Type or namespace definition, or end-of-file expected +* (7,5): error CS0116: A namespace does not directly contain members such as fields or methods +* (8,5): error CS0116: A namespace does not directly contain members such as fields or methods +* (10,5): error CS0116: A namespace does not directly contain members such as fields or methods +* (10,9): error CS0103: The name 'a' does not exist in the current context +* (10,13): error CS0103: The name 'b' does not exist in the current context +* error CS5001: Program does not contain a static 'Main' method suitable for an entry point But this other fragment does work: ``` @@ -57,4 +59,4 @@ class Program Console.ReadLine(); } } -``` \ No newline at end of file +``` From 78bbc8fb7084cdd4a594b25b0e71b06e7583842f Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Fri, 8 Mar 2013 01:24:27 -0300 Subject: [PATCH 0039/1224] Update readme.md --- spikes/DebugSymbols/readme.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spikes/DebugSymbols/readme.md b/spikes/DebugSymbols/readme.md index 6854f0af..f6da3221 100644 --- a/spikes/DebugSymbols/readme.md +++ b/spikes/DebugSymbols/readme.md @@ -10,9 +10,7 @@ DebugSymbols [.csx file] Findings ======== To compile SyntaxTree is being used, could not find a way to build from ScriptEngine. Generating a .pdb file with the current settings seems simple. The following figure shows a debugging session with mdbg (still need to figure out how to get mdbg to recognize the source file). -![alt text][logo] - -[logo]: https://github.com/dschenkelman/scriptcs/blob/dev/spikes/DebugSymbols/debugSession.png "Debugging session" +![debugSession](https://f.cloud.github.com/assets/3376731/235457/97f6f1bc-87a7-11e2-97aa-1d3b9a3cadaf.png) Source needs to be a valid "compilation unit". In the case of a console app, that means having an entry point (main method) and inside a class. For example, this code: ``` From 10fea0a5dfb54deaf07bcc37286db537d475afbb Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Fri, 8 Mar 2013 01:52:35 -0300 Subject: [PATCH 0040/1224] # Deleted spikes folder --- spikes/DebugSymbols/DebugSymbols.sln | 20 ----- spikes/DebugSymbols/DebugSymbols/App.config | 6 -- .../DebugSymbols/DebugSymbols.csproj | 62 -------------- spikes/DebugSymbols/DebugSymbols/Program.cs | 80 ------------------ .../DebugSymbols/Properties/AssemblyInfo.cs | 36 -------- spikes/DebugSymbols/debugSession.png | Bin 68972 -> 0 bytes spikes/DebugSymbols/readme.md | 60 ------------- spikes/DebugSymbols/test.csx | 16 ---- 8 files changed, 280 deletions(-) delete mode 100644 spikes/DebugSymbols/DebugSymbols.sln delete mode 100644 spikes/DebugSymbols/DebugSymbols/App.config delete mode 100644 spikes/DebugSymbols/DebugSymbols/DebugSymbols.csproj delete mode 100644 spikes/DebugSymbols/DebugSymbols/Program.cs delete mode 100644 spikes/DebugSymbols/DebugSymbols/Properties/AssemblyInfo.cs delete mode 100644 spikes/DebugSymbols/debugSession.png delete mode 100644 spikes/DebugSymbols/readme.md delete mode 100644 spikes/DebugSymbols/test.csx diff --git a/spikes/DebugSymbols/DebugSymbols.sln b/spikes/DebugSymbols/DebugSymbols.sln deleted file mode 100644 index fe76c3ee..00000000 --- a/spikes/DebugSymbols/DebugSymbols.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DebugSymbols", "DebugSymbols\DebugSymbols.csproj", "{342F3092-DF0F-4CD4-9C8D-46969097674A}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {342F3092-DF0F-4CD4-9C8D-46969097674A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {342F3092-DF0F-4CD4-9C8D-46969097674A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {342F3092-DF0F-4CD4-9C8D-46969097674A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {342F3092-DF0F-4CD4-9C8D-46969097674A}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/spikes/DebugSymbols/DebugSymbols/App.config b/spikes/DebugSymbols/DebugSymbols/App.config deleted file mode 100644 index 8e156463..00000000 --- a/spikes/DebugSymbols/DebugSymbols/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/spikes/DebugSymbols/DebugSymbols/DebugSymbols.csproj b/spikes/DebugSymbols/DebugSymbols/DebugSymbols.csproj deleted file mode 100644 index 04dfce2a..00000000 --- a/spikes/DebugSymbols/DebugSymbols/DebugSymbols.csproj +++ /dev/null @@ -1,62 +0,0 @@ - - - - - Debug - AnyCPU - {342F3092-DF0F-4CD4-9C8D-46969097674A} - Exe - Properties - DebugSymbols - DebugSymbols - v4.5 - 512 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spikes/DebugSymbols/DebugSymbols/Program.cs b/spikes/DebugSymbols/DebugSymbols/Program.cs deleted file mode 100644 index 329da4e3..00000000 --- a/spikes/DebugSymbols/DebugSymbols/Program.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Roslyn.Compilers; -using Roslyn.Compilers.Common; -using Roslyn.Compilers.CSharp; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DebugSymbols -{ - class Program - { - static void Main(string[] args) - { - if (args.Length == 0) - { - Console.WriteLine("Usage:\r\n\r\nDebugSymbols [.csx file] \r\n"); - Console.ReadKey(); - return; - } - - Console.WriteLine("IMPORTANT"); - Console.WriteLine("================================================"); - Console.WriteLine("In this spike the .csx file must only make use of classes in mscorlib, System and System.Core assemblies."); - Console.WriteLine("================================================"); - Console.WriteLine(); - - var filePath = args[0]; - var fileDir = Path.GetDirectoryName(filePath); - fileDir = Path.IsPathRooted(filePath) ? fileDir : Path.Combine(Environment.CurrentDirectory, fileDir); - var fileName = Path.GetFileName(filePath); - var nameWithoutExtension = fileName.Replace(Path.GetExtension(fileName), string.Empty); - var outputName = nameWithoutExtension + ".exe"; - var outputPath = Path.Combine(fileDir, outputName); - var pdbPath = Path.Combine(fileDir, nameWithoutExtension + ".pdb"); - - var code = File.ReadAllText(filePath); - - var tree = SyntaxTree.ParseText(code); - - var compilation = Compilation.Create("DerivedClass") - .WithOptions(new CompilationOptions(OutputKind.ConsoleApplication, - debugInformationKind: DebugInformationKind.Full, - platform: Platform.AnyCPU)) - .AddSyntaxTrees(tree) - .AddReferences( - MetadataReference.CreateAssemblyReference("mscorlib"), - MetadataReference.CreateAssemblyReference("System"), - MetadataReference.CreateAssemblyReference("System.Core")); - - // need to add assemblies - EmitResult result; - - using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate)) - using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate)) - { - result = compilation.Emit(outputStream, outputName, pdbPath, pdbStream); - } - - if (result.Success) - { - Console.WriteLine("Compilation successful"); - Console.WriteLine(string.Format("Output .exe at {0}", outputPath)); - Console.WriteLine(string.Format("Output .pdb at {0}", pdbPath)); - } - else - { - Console.WriteLine("Compilation failed"); - foreach (var error in result.Diagnostics) - { - Console.WriteLine(error); - } - } - - Console.ReadKey(); - } - } -} \ No newline at end of file diff --git a/spikes/DebugSymbols/DebugSymbols/Properties/AssemblyInfo.cs b/spikes/DebugSymbols/DebugSymbols/Properties/AssemblyInfo.cs deleted file mode 100644 index 0c85c0fc..00000000 --- a/spikes/DebugSymbols/DebugSymbols/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DebugSymbols")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DebugSymbols")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("47c9e190-3721-40db-bb50-f4b39ca26510")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/spikes/DebugSymbols/debugSession.png b/spikes/DebugSymbols/debugSession.png deleted file mode 100644 index 8bab89f553dd56eb4351ba67a703ce3be2329158..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68972 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 z 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 Date: Thu, 7 Mar 2013 23:44:07 -0800 Subject: [PATCH 0041/1224] Adding IScriptPackSession and tests --- src/ScriptCs.Contracts/IScriptPack.cs | 2 +- src/ScriptCs.Contracts/IScriptPackSession.cs | 8 +++++ .../ScriptCs.Contracts.csproj | 4 +-- src/ScriptCs.Core/IScriptEngine.cs | 2 -- .../ISession.cs | 3 +- src/ScriptCs.Core/ScriptCs.Core.csproj | 2 ++ src/ScriptCs.Core/ScriptExecutor.cs | 16 ++++++++-- src/ScriptCs.Core/ScriptHostFactory.cs | 1 + src/ScriptCs.Core/ScriptPackSession.cs | 29 +++++++++++++++++ .../Wrappers/ScriptEngineWrapper.cs | 1 - src/ScriptCs.Core/Wrappers/SessionWrapper.cs | 6 +++- .../ScriptExecutorTests.cs | 31 ++++++++++++++----- 12 files changed, 87 insertions(+), 18 deletions(-) create mode 100644 src/ScriptCs.Contracts/IScriptPackSession.cs rename src/{ScriptCs.Contracts => ScriptCs.Core}/ISession.cs (66%) create mode 100644 src/ScriptCs.Core/ScriptPackSession.cs diff --git a/src/ScriptCs.Contracts/IScriptPack.cs b/src/ScriptCs.Contracts/IScriptPack.cs index 06c29bf8..0174b0e6 100644 --- a/src/ScriptCs.Contracts/IScriptPack.cs +++ b/src/ScriptCs.Contracts/IScriptPack.cs @@ -10,7 +10,7 @@ namespace ScriptCs.Contracts [InheritedExport] public interface IScriptPack { - void Initialize(ISession session); + void Initialize(IScriptPackSession session); IScriptPackContext GetContext(); void Terminate(); } diff --git a/src/ScriptCs.Contracts/IScriptPackSession.cs b/src/ScriptCs.Contracts/IScriptPackSession.cs new file mode 100644 index 00000000..8f74897f --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptPackSession.cs @@ -0,0 +1,8 @@ +namespace ScriptCs.Contracts +{ + public interface IScriptPackSession + { + void AddReference(string assemblyDisplayNameOrPath); + void ImportNamespace(string @namespace); + } +} diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 8e11be08..832c8e3d 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -7,7 +7,7 @@ {6049E205-8B5F-4080-B023-70600E51FD64} Library Properties - ScriptCs.Contracts + ScriptCs.Core ScriptCs.Contracts v4.5 512 @@ -55,7 +55,7 @@ - + diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index df07b55b..b0b698f7 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -1,8 +1,6 @@ using System; using System.ComponentModel.Composition; - using Roslyn.Scripting; -using ScriptCs.Contracts; namespace ScriptCs { diff --git a/src/ScriptCs.Contracts/ISession.cs b/src/ScriptCs.Core/ISession.cs similarity index 66% rename from src/ScriptCs.Contracts/ISession.cs rename to src/ScriptCs.Core/ISession.cs index e87d1610..69b8f165 100644 --- a/src/ScriptCs.Contracts/ISession.cs +++ b/src/ScriptCs.Core/ISession.cs @@ -1,8 +1,9 @@ -namespace ScriptCs.Contracts +namespace ScriptCs { public interface ISession { object Execute(string code); void AddReference(string assemblyDisplayNameOrPath); + void ImportNamespace(string @namespace); } } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index da9ab359..41d45552 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -64,6 +64,7 @@ + @@ -78,6 +79,7 @@ + diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 50e28811..1339d8e8 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,9 +1,9 @@ using System; using Roslyn.Scripting.CSharp; -using ScriptCs.Contracts; using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; +using ScriptCs.Contracts; namespace ScriptCs { @@ -43,10 +43,12 @@ public void Execute(string script, IEnumerable paths, IEnumerable PrepareBinFolder(IEnumerable paths, string bin) @@ -85,7 +87,7 @@ private IEnumerable GetContexts(IEnumerable scr } } - private void InitializeScriptPacks(IEnumerable scriptPacks, ISession session) + private void InitializeScriptPacks(IEnumerable scriptPacks, IScriptPackSession session) { foreach (var pack in scriptPacks) { @@ -93,5 +95,13 @@ private void InitializeScriptPacks(IEnumerable scriptPacks, ISessio } } + private void TerminateScriptPacks(IEnumerable scriptPacks) + { + foreach (var pack in scriptPacks) + { + pack.Terminate(); + } + } + } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptHostFactory.cs b/src/ScriptCs.Core/ScriptHostFactory.cs index 76988199..684f2d7e 100644 --- a/src/ScriptCs.Core/ScriptHostFactory.cs +++ b/src/ScriptCs.Core/ScriptHostFactory.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using ScriptCs.Contracts; + namespace ScriptCs { public class ScriptHostFactory : IScriptHostFactory diff --git a/src/ScriptCs.Core/ScriptPackSession.cs b/src/ScriptCs.Core/ScriptPackSession.cs new file mode 100644 index 00000000..4cd80fdc --- /dev/null +++ b/src/ScriptCs.Core/ScriptPackSession.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public class ScriptPackSession : IScriptPackSession + { + private readonly ISession _session; + + public ScriptPackSession(ISession session) + { + _session = session; + } + + public void AddReference(string assemblyDisplayNameOrPath) + { + _session.AddReference(assemblyDisplayNameOrPath); + } + + public void ImportNamespace(string ns) + { + + } + } +} diff --git a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs index e8c76214..e928c8e9 100644 --- a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs @@ -1,6 +1,5 @@ using Roslyn.Scripting; using Roslyn.Scripting.CSharp; -using ScriptCs.Contracts; namespace ScriptCs.Wrappers { diff --git a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs index e1a8306e..23a09331 100644 --- a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs @@ -1,5 +1,4 @@ using Roslyn.Scripting; -using ScriptCs.Contracts; namespace ScriptCs.Wrappers { @@ -21,5 +20,10 @@ public void AddReference(string assemblyDisplayNameOrPath) { this._session.AddReference(assemblyDisplayNameOrPath); } + + public void ImportNamespace(string @namespace) + { + this._session.ImportNamespace(@namespace); + } } } diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 927c4d77..adde9e11 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using Moq; +using ScriptCs; using ScriptCs.Contracts; using Should; using Xunit; @@ -221,14 +222,11 @@ public void ShouldInitializeScriptPacks() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - // var scriptPack2 = new Mock(); - // scriptPack2.Setup(p => p.Initialize(It.IsAny())); - + executor.Execute("script.csx", Enumerable.Empty(), new List { scriptPack1.Object }); - scriptPack1.Verify(p => p.Initialize(It.IsAny())); - // scriptPack2.Verify(p => p.Initialize(It.IsAny())); + scriptPack1.Verify(p => p.Initialize(It.IsAny())); } [Fact] @@ -271,7 +269,26 @@ public void ShouldCreateSessionWithScriptHost() engine.Setup(e => e.CreateSession(It.IsAny())).Returns(new Mock().Object); executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); engine.Verify(e=>e.CreateSession(It.IsAny())); - } + } + + [Fact] + public void ShouldTerminateScriptPacksWhenScriptFinishes() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); + + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + + executor.Execute("script.csx", Enumerable.Empty(), new List { scriptPack1.Object }); + scriptPack1.Verify(p => p.Terminate()); + } } } From 1ccd8cdb22bb76bbf371328d54c09f7aeb1879a8 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Fri, 8 Mar 2013 18:17:34 -0500 Subject: [PATCH 0042/1224] Add xunit assemblies to the repository. --- tools/xunit/xunit.runner.msbuild.dll | Bin 0 -> 25088 bytes tools/xunit/xunit.runner.utility.dll | Bin 0 -> 47104 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/xunit/xunit.runner.msbuild.dll create mode 100644 tools/xunit/xunit.runner.utility.dll diff --git a/tools/xunit/xunit.runner.msbuild.dll b/tools/xunit/xunit.runner.msbuild.dll new file mode 100644 index 0000000000000000000000000000000000000000..da6cff1e211a5af870b0933fb754185890abd1ea GIT binary patch literal 25088 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 B!cYJJ literal 0 HcmV?d00001 diff --git a/tools/xunit/xunit.runner.utility.dll b/tools/xunit/xunit.runner.utility.dll new file mode 100644 index 0000000000000000000000000000000000000000..8c0e61c3f1a2de5663b0862acd8cfa6d51986545 GIT binary patch literal 47104 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 Date: Fri, 8 Mar 2013 18:30:04 -0500 Subject: [PATCH 0043/1224] Move common project configuration settings into shared files. Common build configuration properties are moved into build\ScriptCs.Common.props, which is imported by each *.csproj file in the solution. Common assembly attribute declarations can be found in CommonAssemblyInfo.cs and CommonVersionInfo.cs. --- build/ScriptCs.Common.props | 49 +++++++++++++++++ common/CommonAssemblyInfo.cs | 0 common/CommonVersionInfo.cs | 0 .../Properties/AssemblyInfo.cs | 33 +----------- .../ScriptCs.Contracts.csproj | 45 ++++------------ src/ScriptCs.Core/Properties/AssemblyInfo.cs | 28 ---------- src/ScriptCs.Core/ScriptCs.Core.csproj | 42 ++++----------- src/ScriptCs/Properties/AssemblyInfo.cs | 30 +---------- src/ScriptCs/ScriptCs.csproj | 53 ++++--------------- .../Properties/AssemblyInfo.cs | 29 ---------- .../ScriptCs.Core.Tests.csproj | 44 ++++----------- .../ScriptCs.Tests/Properties/AssemblyInfo.cs | 29 ---------- test/ScriptCs.Tests/ScriptCs.Tests.csproj | 47 ++++------------ 13 files changed, 102 insertions(+), 327 deletions(-) create mode 100644 build/ScriptCs.Common.props create mode 100644 common/CommonAssemblyInfo.cs create mode 100644 common/CommonVersionInfo.cs diff --git a/build/ScriptCs.Common.props b/build/ScriptCs.Common.props new file mode 100644 index 00000000..fa04ec5a --- /dev/null +++ b/build/ScriptCs.Common.props @@ -0,0 +1,49 @@ + + + + + + Debug + AnyCPU + + Properties + v4.5 + 512 + + ..\..\ + true + + true + prompt + 4 + bin\$(Configuration)\ + + true + + TRACE;$(DefineConstants) + + + + $(MSBuildProjectName)\bin\ + $(MSBuildProjectName)\obj\ + + $([System.IO.Path]::Combine($(ArtifactsPath), $(ProjectOutputPath))) + $([System.IO.Path]::Combine($(ArtifactsPath), $(ProjectIntermediatePath))) + + + + false + + + + DEBUG;CODE_ANALYSIS;$(DefineConstants) + full + false + + + + pdbonly + true + + \ No newline at end of file diff --git a/common/CommonAssemblyInfo.cs b/common/CommonAssemblyInfo.cs new file mode 100644 index 00000000..e69de29b diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs new file mode 100644 index 00000000..e69de29b diff --git a/src/ScriptCs.Contracts/Properties/AssemblyInfo.cs b/src/ScriptCs.Contracts/Properties/AssemblyInfo.cs index ea535fa1..cb1fda07 100644 --- a/src/ScriptCs.Contracts/Properties/AssemblyInfo.cs +++ b/src/ScriptCs.Contracts/Properties/AssemblyInfo.cs @@ -1,36 +1,7 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("scriptcs.contracts")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("scriptcs.contracts")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] +[assembly: AssemblyTitle("ScriptCs.Contracts")] +[assembly: AssemblyDescription("This assembly contains the components necessary to create script packs for scriptcs.")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("a0cbc203-deff-4b7c-b414-11797b7a3100")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 832c8e3d..e410c747 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -1,38 +1,12 @@  - + - Debug - AnyCPU {6049E205-8B5F-4080-B023-70600E51FD64} Library - Properties - ScriptCs.Core + ScriptCs.Contracts ScriptCs.Contracts - v4.5 - 512 - - ..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false + ..\..\ @@ -56,6 +30,12 @@ + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + @@ -63,11 +43,4 @@ - \ No newline at end of file diff --git a/src/ScriptCs.Core/Properties/AssemblyInfo.cs b/src/ScriptCs.Core/Properties/AssemblyInfo.cs index b594a7cb..f96afe0e 100644 --- a/src/ScriptCs.Core/Properties/AssemblyInfo.cs +++ b/src/ScriptCs.Core/Properties/AssemblyInfo.cs @@ -1,35 +1,7 @@ using System.Reflection; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. [assembly: AssemblyTitle("ScriptCs.Core")] [assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScriptCs.Core")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("4c4ebd22-f4b0-47de-a417-f0a2a127508c")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 41d45552..547cdf31 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -1,35 +1,12 @@  - + - Debug - AnyCPU {E590E710-E159-48E6-A3E6-1A83D3FE732C} Library - Properties ScriptCs ScriptCs.Core - v4.5 - 512 ..\..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 @@ -55,6 +32,12 @@ + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + @@ -87,18 +70,11 @@ - + {6049e205-8b5f-4080-b023-70600e51fd64} - Scriptcs.Contracts + ScriptCs.Contracts - \ No newline at end of file diff --git a/src/ScriptCs/Properties/AssemblyInfo.cs b/src/ScriptCs/Properties/AssemblyInfo.cs index 47912fde..ffda0bf0 100644 --- a/src/ScriptCs/Properties/AssemblyInfo.cs +++ b/src/ScriptCs/Properties/AssemblyInfo.cs @@ -1,36 +1,10 @@ using System.Reflection; -using System.Runtime.CompilerServices; +using System.Resources; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. [assembly: AssemblyTitle("scriptcs")] [assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScriptCs")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("f624ee58-910a-4541-a46f-afcd3edca9df")] -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: NeutralResourcesLanguage("en-US")] diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index f45d1c02..4c6fe27e 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -1,41 +1,11 @@  - + - Debug - AnyCPU {25080671-1A80-4041-B9C7-260578FF4849} Exe - Properties ScriptCs scriptcs - v4.5 - 512 - - ..\ - true - - - AnyCPU - true - full - false - bin\debug\ - DEBUG;TRACE - prompt - 4 - false - true - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false @@ -48,6 +18,12 @@ + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + @@ -55,22 +31,15 @@ - + {6049e205-8b5f-4080-b023-70600e51fd64} - Scriptcs.Contracts + ScriptCs.Contracts - + {e590e710-e159-48e6-a3e6-1a83d3fe732c} - Scriptcs.Core + ScriptCs.Core - \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/Properties/AssemblyInfo.cs b/test/ScriptCs.Core.Tests/Properties/AssemblyInfo.cs index 159ddbd1..febbab00 100644 --- a/test/ScriptCs.Core.Tests/Properties/AssemblyInfo.cs +++ b/test/ScriptCs.Core.Tests/Properties/AssemblyInfo.cs @@ -1,36 +1,7 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. [assembly: AssemblyTitle("ScriptCs.Core.Tests")] [assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScriptCs.Core.Tests")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("fe718b7f-5fb4-43eb-a3da-26a1d25e644c")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index d58e57df..b0965369 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -1,35 +1,12 @@  - + - Debug - AnyCPU {AC228213-7356-4F0D-BA48-EBA5FB8A7506} Library - Properties - ScriptCs + ScriptCs.Tests ScriptCs.Core.Tests - v4.5 - 512 ..\..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 @@ -55,6 +32,12 @@ + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + @@ -66,9 +49,9 @@ {6049e205-8b5f-4080-b023-70600e51fd64} ScriptCs.Contracts - + {e590e710-e159-48e6-a3e6-1a83d3fe732c} - Scriptcs.Core + ScriptCs.Core @@ -76,11 +59,4 @@ - \ No newline at end of file diff --git a/test/ScriptCs.Tests/Properties/AssemblyInfo.cs b/test/ScriptCs.Tests/Properties/AssemblyInfo.cs index 319eb29c..3180a546 100644 --- a/test/ScriptCs.Tests/Properties/AssemblyInfo.cs +++ b/test/ScriptCs.Tests/Properties/AssemblyInfo.cs @@ -1,36 +1,7 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. [assembly: AssemblyTitle("ScriptCs.Tests")] [assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScriptCs.Tests")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("96733f0d-6fa4-4f6d-8f69-e4718eaf48b7")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index e376ff63..bb1d3b3a 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -1,38 +1,12 @@  - + - Debug - AnyCPU {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE} Library - Properties ScriptCs.Tests ScriptCs.Tests - v4.5 - 512 - ..\..\src\ - true - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false + ..\..\ @@ -53,12 +27,18 @@ + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + - + {25080671-1a80-4041-b9c7-260578ff4849} - Scriptcs + ScriptCs @@ -66,11 +46,4 @@ - \ No newline at end of file From 9d8fc5205d054bf9b45be91ac3e1efd9b7b7fa77 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Fri, 8 Mar 2013 18:31:22 -0500 Subject: [PATCH 0044/1224] Add a build script to the solution. #26 --- .gitignore | 2 ++ ScriptCs.sln | 8 +++++++ build.cmd | 27 ++++++++++++++++++++++ build/Build.proj | 44 ++++++++++++++++++++++++++++++++++++ build/ScriptCs.Version.props | 29 ++++++++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 build.cmd create mode 100644 build/Build.proj create mode 100644 build/ScriptCs.Version.props diff --git a/.gitignore b/.gitignore index bdc3535f..11b6d0f7 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,5 @@ Generated_Code #added for RIA/Silverlight projects _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML + +artifacts \ No newline at end of file diff --git a/ScriptCs.sln b/ScriptCs.sln index eb2cfee1..8fa69ec7 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -20,6 +20,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Core", "src\Script EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Core.Tests", "test\ScriptCs.Core.Tests\ScriptCs.Core.Tests.csproj", "{AC228213-7356-4F0D-BA48-EBA5FB8A7506}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{9659F354-CF48-4FD6-8E0C-E9EB3C2BDA32}" + ProjectSection(SolutionItems) = preProject + build\Build.proj = build\Build.proj + build\Build.tasks = build\Build.tasks + build\ScriptCs.Common.props = build\ScriptCs.Common.props + build\ScriptCs.Version.props = build\ScriptCs.Version.props + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/build.cmd b/build.cmd new file mode 100644 index 00000000..031d52ed --- /dev/null +++ b/build.cmd @@ -0,0 +1,27 @@ +@echo Off +setlocal + +set EnableNuGetPackageRestore=true + +if exist artifacts goto Build +mkdir artifacts + +:Build +%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild Build\Build.proj /nologo /m /v:M %* /fl /flp:LogFile=artifacts\msbuild.log;Verbosity=Detailed;DetailedSummary /nr:false + +if %ERRORLEVEL% neq 0 goto BuildFail +goto BuildSuccess + +:BuildFail +echo. +echo *** BUILD FAILED *** +goto End + +:BuildSuccess +echo. +echo **** BUILD SUCCESSFUL *** +goto end + +:End +echo. +endlocal \ No newline at end of file diff --git a/build/Build.proj b/build/Build.proj new file mode 100644 index 00000000..2dd60173 --- /dev/null +++ b/build/Build.proj @@ -0,0 +1,44 @@ + + + + + + Debug + + $([System.IO.Path]::GetFullPath( '$(MSBuildThisFileDirectory)..\' )) + $([System.IO.Path]::Combine( $(Root), 'artifacts\' )) + $([System.IO.Path]::Combine( $(BaseArtifactsPath), $(Configuration) ))\ + + + + + + Configuration=$(Configuration); + ArtifactsPath=$(ArtifactsPath) + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props new file mode 100644 index 00000000..5bc2a765 --- /dev/null +++ b/build/ScriptCs.Version.props @@ -0,0 +1,29 @@ + + + + + + 0 + 1 + 0 + + + + + + + + + $(MajorVersion).$(MinorVersion).0 + $(MajorVersion).$(MinorVersion).$(PatchVersion) + $(PackageVersion)-$(BuildQuality) + + + \ No newline at end of file From 89a32618dce7584de7bf8711b42a6dc6fd0248c0 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sat, 9 Mar 2013 20:43:54 -0300 Subject: [PATCH 0045/1224] # Initial version of DebugFilePreProcessor.cs and DebugScriptExecutor.cs with tests for DebugFilePreProcessor.cs --- src/ScriptCs.Core/DebugFilePreProcessor.cs | 25 ++++++ src/ScriptCs.Core/DebugScriptExecutor.cs | 15 ++++ src/ScriptCs.Core/FilePreProcessor.cs | 10 ++- src/ScriptCs.Core/ScriptCs.Core.csproj | 2 + src/ScriptCs.Core/ScriptExecutor.cs | 21 +++-- .../DebugFilePreProcessorTests.cs | 82 +++++++++++++++++++ .../DebugScriptExecutorTests.cs | 48 +++++++++++ .../ScriptCs.Core.Tests.csproj | 8 +- .../ScriptExecutorTests.cs | 24 +++--- 9 files changed, 210 insertions(+), 25 deletions(-) create mode 100644 src/ScriptCs.Core/DebugFilePreProcessor.cs create mode 100644 src/ScriptCs.Core/DebugScriptExecutor.cs create mode 100644 test/ScriptCs.Core.Tests/DebugFilePreProcessorTests.cs create mode 100644 test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs diff --git a/src/ScriptCs.Core/DebugFilePreProcessor.cs b/src/ScriptCs.Core/DebugFilePreProcessor.cs new file mode 100644 index 00000000..7a3ac7b3 --- /dev/null +++ b/src/ScriptCs.Core/DebugFilePreProcessor.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ScriptCs +{ + public class DebugFilePreProcessor : FilePreProcessor + { + private const string SystemDiagnosticsUsing = "using System.Diagnostics;"; + + public DebugFilePreProcessor(IFileSystem fileSystem) + : base(fileSystem) + { + } + + protected override string GenerateUsings(ICollection usingLines) + { + if (usingLines.Count(l => l.Equals(SystemDiagnosticsUsing)) == 0) + { + usingLines.Add(SystemDiagnosticsUsing); + } + + return string.Join(_fileSystem.NewLine, usingLines); + } + } +} diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs new file mode 100644 index 00000000..03424f84 --- /dev/null +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -0,0 +1,15 @@ +namespace ScriptCs +{ + public class DebugScriptExecutor : ScriptExecutor + { + public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) + : base(fileSystem, filePreProcessor, scriptEngine, scriptHostFactory) + { + } + + public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) + : base(fileSystem, filePreProcessor, scriptEngine) + { + } + } +} diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 179f39d4..353cb88d 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -12,7 +12,7 @@ public class FilePreProcessor : IFilePreProcessor private const string LoadString = "#load "; private const string UsingString = "using "; - private readonly IFileSystem _fileSystem; + protected readonly IFileSystem _fileSystem; [ImportingConstructor] public FilePreProcessor(IFileSystem fileSystem) @@ -25,12 +25,18 @@ public string ProcessFile(string path) var entryFile = _fileSystem.ReadFileLines(path); var parsed = ParseFile(entryFile); - var result = string.Join(_fileSystem.NewLine, parsed.Item1); + // item1 === usings; item2 === code + var result = this.GenerateUsings(parsed.Item1); result += _fileSystem.NewLine + parsed.Item2; return result; } + protected virtual string GenerateUsings(ICollection usingLines) + { + return string.Join(_fileSystem.NewLine, usingLines); + } + private Tuple, string> ParseFile(IEnumerable file) { var usings = new List(); diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 547cdf31..c7b2bfee 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -31,6 +31,8 @@ + + Properties\CommonAssemblyInfo.cs diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 1339d8e8..90d0f2cf 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,6 +1,4 @@ -using System; -using Roslyn.Scripting.CSharp; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; using ScriptCs.Contracts; @@ -26,13 +24,13 @@ public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) : this(fileSystem, filePreProcessor, scriptEngine, new ScriptHostFactory()) { - + } public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) { - _scriptEngine.AddReference("System"); - _scriptEngine.AddReference("System.Core"); + this._scriptEngine.AddReference("System"); + this._scriptEngine.AddReference("System.Core"); var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); @@ -47,10 +45,15 @@ public void Execute(string script, IEnumerable paths, IEnumerable PrepareBinFolder(IEnumerable paths, string bin) { var files = new List(); @@ -67,7 +70,7 @@ private IEnumerable PrepareBinFolder(IEnumerable paths, string b _fileSystem.Copy(file, destFile, true); files.Add(destFile); } - + return files; } @@ -85,7 +88,7 @@ private IEnumerable GetContexts(IEnumerable scr { yield return pack.GetContext(); } - } + } private void InitializeScriptPacks(IEnumerable scriptPacks, IScriptPackSession session) { diff --git a/test/ScriptCs.Core.Tests/DebugFilePreProcessorTests.cs b/test/ScriptCs.Core.Tests/DebugFilePreProcessorTests.cs new file mode 100644 index 00000000..03362a3f --- /dev/null +++ b/test/ScriptCs.Core.Tests/DebugFilePreProcessorTests.cs @@ -0,0 +1,82 @@ +using Moq; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + using System; + using System.Collections.Generic; + using System.Linq; + + public class DebugFilePreProcessorTests + { + private static DebugFilePreProcessor CreateFilePreProcessor(Mock fileSystem = null) + { + fileSystem = fileSystem ?? new Mock(); + + return new DebugFilePreProcessor(fileSystem.Object); + } + + public class TheParseFileMethod + { + private List fileWithoutSystemDiagnostics = new List + { + "using System;", + "using System.Collections.Generic;", + @"Console.WriteLine(""Hello Script 3"");", + @"Console.WriteLine(""Goodbye Script 3"");" + }; + + private List fileWithSystemDiagnostics = new List + { + "using System;", + "using System.Diagnostics;", + "using System.Collections.Generic;", + @"Console.WriteLine(""Hello Script 3"");", + @"Debug.WriteLine(""Hello Script 3"");", + @"Console.WriteLine(""Goodbye Script 3"");" + }; + + private Mock _fileSystem; + + public TheParseFileMethod() + { + _fileSystem = new Mock(); + _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); + } + + [Fact] + public void ShouldAddSystemDiagnosticsUsingIfItDoesNotExistInOriginalCode() + { + // arrange + const string FilePath = "C:\filePath.csx"; + _fileSystem.Setup(fs => fs.ReadFileLines(FilePath)).Returns(this.fileWithoutSystemDiagnostics.ToArray()); + + var preProcessor = CreateFilePreProcessor(_fileSystem); + + // act + var processedCode = preProcessor.ProcessFile(FilePath); + + // assert + processedCode.ShouldContain("using System.Diagnostics;"); + } + + [Fact] + public void ShouldNotAddSystemDiagnosticsUsingIfItExistsInOriginalCode() + { + // arrange + const string FilePath = "C:\filePath.csx"; + _fileSystem.Setup(fs => fs.ReadFileLines(FilePath)).Returns(this.fileWithSystemDiagnostics.ToArray()); + + var preProcessor = CreateFilePreProcessor(_fileSystem); + + // act + var processedCode = preProcessor.ProcessFile(FilePath); + + // assert + var lines = processedCode.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + lines.Count(l => l.Equals("using System.Diagnostics;")).ShouldEqual(1); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs new file mode 100644 index 00000000..ee18920d --- /dev/null +++ b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs @@ -0,0 +1,48 @@ +using Moq; + +namespace ScriptCs.Tests +{ + using Xunit; + + public class DebugScriptExecutorTests + { + public static ScriptExecutor CreateScriptExecutor( + Mock fileSystem = null, + Mock fileProcessor = null, + Mock scriptEngine = null, + Mock scriptHostFactory = null) + { + fileSystem = fileSystem ?? new Mock(); + + fileProcessor = fileProcessor ?? new Mock(); + + if (scriptEngine == null) + { + var mockSession = new Mock(); + mockSession.Setup(s => s.AddReference(It.IsAny())); + mockSession.Setup(s => s.Execute(It.IsAny())).Returns(new object()); + + scriptEngine = new Mock(); + scriptEngine.SetupProperty(e => e.BaseDirectory); + scriptEngine.Setup(e => e.CreateSession()).Returns(mockSession.Object); + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(mockSession.Object); + } + + if (scriptHostFactory == null) + { + return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); + } + + return new ScriptExecutor( + fileSystem.Object, fileProcessor.Object, scriptEngine.Object, scriptHostFactory.Object); + } + + public class TheExecuteMethod + { + [Fact(Skip = "No code yet")] + public void ShouldAddSystemDiagnosticsUsingAutomaticallyWhenDebugging() + { + } + } + } +} diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index b0965369..9f28e7d7 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -22,11 +22,7 @@ - - - - ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll @@ -38,6 +34,7 @@ Properties\CommonVersionInfo.cs + @@ -57,6 +54,9 @@ + + + \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 39f99f0f..f5521a54 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -12,7 +12,7 @@ namespace ScriptCs.Tests { public class ScriptExecutorTests { - private static ScriptExecutor CreateScriptExecutor( + public static ScriptExecutor CreateScriptExecutor( Mock fileSystem = null, Mock fileProcessor = null, Mock scriptEngine = null, @@ -44,7 +44,7 @@ private static ScriptExecutor CreateScriptExecutor( } } - public class TheExecuteMethod + public class TheExecuteMethod { [Fact] public void ConstructsAbsolutePathBeforePreProcessingFile() @@ -52,7 +52,7 @@ public void ConstructsAbsolutePathBeforePreProcessingFile() var fileSystem = new Mock(); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - + var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); @@ -74,7 +74,7 @@ public void DoNotChangePathIfAbsolute() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); - + preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -190,7 +190,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInSessionWhenExecuteIsIn fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); var scriptExecutor = CreateScriptExecutor( - fileSystem: fileSystem, + fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: scriptEngine); @@ -223,7 +223,7 @@ public void ShouldInitializeScriptPacks() var scriptPack1 = new Mock(); scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - + executor.Execute("script.csx", Enumerable.Empty(), new List { scriptPack1.Object }); scriptPack1.Verify(p => p.Initialize(It.IsAny())); } @@ -267,9 +267,9 @@ public void ShouldCreateSessionWithScriptHost() engine.Setup(e => e.CreateSession(It.IsAny())).Returns(new Mock().Object); executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); - engine.Verify(e=>e.CreateSession(It.IsAny())); + engine.Verify(e => e.CreateSession(It.IsAny())); } - + [Fact] public void ShouldTerminateScriptPacksWhenScriptFinishes() { @@ -290,7 +290,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() } [Fact] - public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() + public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() { // arrange var fileSystem = new Mock(); @@ -302,11 +302,12 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var destinationFilePath = Path.Combine(currentDirectory, @"bin\fileName.cs"); var scriptName = "script.csx"; - var paths = new string[]{ sourceFilePath }; + var paths = new string[] { sourceFilePath }; var sourceWriteTime = new DateTime(2013, 3, 7); var destinatioWriteTime = new DateTime(2013, 3, 8); + fileSystem.Setup(fs => fs.GetWorkingDirectory(scriptName)).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); @@ -339,6 +340,7 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var sourceWriteTime = new DateTime(2013, 3, 7); var destinatioWriteTime = sourceWriteTime; + fileSystem.Setup(fs => fs.GetWorkingDirectory(scriptName)).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); @@ -376,8 +378,10 @@ public void ShouldAddReferenceToEachDestinationFile() var destinationFilePath4 = Path.Combine(currentDirectory, @"bin\fileName4.cs"); var scriptName = "script.csx"; + var paths = new string[] { sourceFilePath1, sourceFilePath2, sourceFilePath3, sourceFilePath4 }; + fileSystem.Setup(fs => fs.GetWorkingDirectory(scriptName)).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); session.Setup(e => e.AddReference(destinationFilePath1)).Verifiable(); From 001c952dffcfff8f2632d3b2f09a40c2dd02e753 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 9 Mar 2013 19:34:33 -0500 Subject: [PATCH 0046/1224] fixed breaking tests. Please setup fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())) for correct path --- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 39f99f0f..f7d6c204 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -308,6 +308,7 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var destinatioWriteTime = new DateTime(2013, 3, 8); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); @@ -340,6 +341,7 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var destinatioWriteTime = sourceWriteTime; fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); @@ -358,6 +360,7 @@ public void ShouldAddReferenceToEachDestinationFile() { // arrange var fileSystem = new Mock(); + var scriptEngine = new Mock(); var session = new Mock(); @@ -379,6 +382,7 @@ public void ShouldAddReferenceToEachDestinationFile() var paths = new string[] { sourceFilePath1, sourceFilePath2, sourceFilePath3, sourceFilePath4 }; fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); session.Setup(e => e.AddReference(destinationFilePath1)).Verifiable(); session.Setup(e => e.AddReference(destinationFilePath2)).Verifiable(); From 074c95362c67ea87b9b9561b903ba09018e36ce5 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 9 Mar 2013 19:35:42 -0500 Subject: [PATCH 0047/1224] reverted to look for packages.config at the working directory level --- src/ScriptCs.Core/Package/PackageContainer.cs | 2 +- src/ScriptCs.Core/PackageAssemblyResolver.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index be3670de..91b939e0 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -16,7 +16,7 @@ public IPackageObject FindPackage(string path, string packageId) public IEnumerable FindReferences(string path) { - var packageReferenceFile = new PackageReferenceFile(path + @"/" + Constants.PackagesFile); + var packageReferenceFile = new PackageReferenceFile(path); var references = packageReferenceFile.GetPackageReferences(); if (references == null) return Enumerable.Empty(); diff --git a/src/ScriptCs.Core/PackageAssemblyResolver.cs b/src/ScriptCs.Core/PackageAssemblyResolver.cs index 58ccd77a..951be349 100644 --- a/src/ScriptCs.Core/PackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/PackageAssemblyResolver.cs @@ -22,10 +22,11 @@ public PackageAssemblyResolver(IFileSystem fileSystem, IPackageContainer package public IEnumerable GetAssemblyNames(string workingDirectory) { var packageDir = Path.Combine(workingDirectory, Constants.PackagesFolder); - if (!_fileSystem.DirectoryExists(packageDir) || !_fileSystem.FileExists(Path.Combine(packageDir, Constants.PackagesFile))) + var packageFilePath = Path.Combine(workingDirectory, Constants.PackagesFile); + if (!_fileSystem.DirectoryExists(packageDir) || !_fileSystem.FileExists(packageFilePath)) return Enumerable.Empty(); - var packages = _packageContainer.FindReferences(packageDir); + var packages = _packageContainer.FindReferences(packageFilePath); var foundAssemblyPaths = new List(); var missingAssemblies = new List(); From 26a12cd48bfee6278b49796e6b78e6b28956032d Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 9 Mar 2013 17:03:46 -0800 Subject: [PATCH 0048/1224] Update CONTRIBUTING.md --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bd8c43a8..654db776 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,11 +2,14 @@ Before submitting a feature or substantial code contribution please discuss it with the team in our [discussion group](https://groups.google.com/forum/?fromgroups#!forum/scriptcs). +Also please see the discussion [here] on which things are open for contribution (https://github.com/scriptcs/scriptcs/issues/79) + ## Workflow * We use the **dev** branch for active development. All pull requests should be made to this branch. * The master branch is only updated via pull requests from the dev branch. * Tests need to be provided for every bug/feature that is completed. +* Please do not submit a PR unless without running all unit tests. If any tests are failing in the PR they will be rejected. ## Issue Management From a49922cc1811b2ef6ba26fcdeddbd6a3cd348e26 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 10 Mar 2013 14:05:51 -0300 Subject: [PATCH 0049/1224] # Initial tests for DebugScriptExecutor.cs --- src/ScriptCs.Core/DebugScriptExecutor.cs | 25 +++++ src/ScriptCs.Core/FileSystem.cs | 5 + src/ScriptCs.Core/ICompilation.cs | 10 ++ src/ScriptCs.Core/IFileSystem.cs | 4 + src/ScriptCs.Core/ISession.cs | 2 + src/ScriptCs.Core/ISubmission.cs | 7 ++ src/ScriptCs.Core/ScriptCs.Core.csproj | 4 + src/ScriptCs.Core/ScriptExecutor.cs | 12 +- .../Wrappers/CompilationWrapper.cs | 21 ++++ .../Wrappers/ScriptEngineWrapper.cs | 11 +- src/ScriptCs.Core/Wrappers/SessionWrapper.cs | 14 +++ .../Wrappers/SubmissionWrapper.cs | 26 +++++ .../DebugScriptExecutorTests.cs | 104 ++++++++++++++++-- .../ScriptCs.Core.Tests.csproj | 1 + .../ScriptExecutorTests.cs | 9 +- 15 files changed, 230 insertions(+), 25 deletions(-) create mode 100644 src/ScriptCs.Core/ICompilation.cs create mode 100644 src/ScriptCs.Core/ISubmission.cs create mode 100644 src/ScriptCs.Core/Wrappers/CompilationWrapper.cs create mode 100644 src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index 03424f84..7ed3929d 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -1,5 +1,10 @@ namespace ScriptCs { + using System; + using System.IO; + + using Roslyn.Compilers.Common; + public class DebugScriptExecutor : ScriptExecutor { public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) @@ -11,5 +16,25 @@ public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProc : base(fileSystem, filePreProcessor, scriptEngine) { } + + protected override void Execute(string absolutePathToScript, ISession session, string code) + { + var fileName = Path.GetFileName(absolutePathToScript); + var nameWithoutExtension = fileName.Replace(Path.GetExtension(fileName), string.Empty); + var outputName = nameWithoutExtension + ".dll"; + var pdbName = nameWithoutExtension + ".pdb"; + var outputPath = Path.Combine(session.Engine.BaseDirectory, outputName); + var pdbPath = Path.Combine(session.Engine.BaseDirectory, pdbName); + + ISubmission submission = session.CompileSubmission(code); + + CommonEmitResult result; + + using (Stream outputStream = _fileSystem.CreateFileStream(outputPath, FileMode.OpenOrCreate)) + using (Stream pdbStream = _fileSystem.CreateFileStream(pdbPath, FileMode.OpenOrCreate)) + { + result = submission.Compilation.Emit(outputStream, pdbStream); + } + } } } diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index f7dfafbd..53a54403 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -66,6 +66,11 @@ public bool FileExists(string path) return File.Exists(path); } + public Stream CreateFileStream(string filePath, FileMode mode) + { + return new FileStream(filePath, mode); + } + public string GetWorkingDirectory(string path) { return IsPathRooted(path) ? Path.GetDirectoryName(path) : CurrentDirectory; diff --git a/src/ScriptCs.Core/ICompilation.cs b/src/ScriptCs.Core/ICompilation.cs new file mode 100644 index 00000000..febf3aac --- /dev/null +++ b/src/ScriptCs.Core/ICompilation.cs @@ -0,0 +1,10 @@ +using System.IO; +using Roslyn.Compilers.Common; + +namespace ScriptCs +{ + public interface ICompilation + { + CommonEmitResult Emit(Stream outputStream, Stream pdbStream); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 6e5aa1e7..d7282763 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -4,6 +4,8 @@ namespace ScriptCs { + using System.IO; + [InheritedExport] public interface IFileSystem { @@ -32,5 +34,7 @@ public interface IFileSystem void Move(string source, string dest); bool FileExists(string path); + + Stream CreateFileStream(string filePath, FileMode mode); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ISession.cs b/src/ScriptCs.Core/ISession.cs index 69b8f165..5abcd9ae 100644 --- a/src/ScriptCs.Core/ISession.cs +++ b/src/ScriptCs.Core/ISession.cs @@ -2,8 +2,10 @@ { public interface ISession { + IScriptEngine Engine { get; } object Execute(string code); void AddReference(string assemblyDisplayNameOrPath); void ImportNamespace(string @namespace); + ISubmission CompileSubmission(string code); } } diff --git a/src/ScriptCs.Core/ISubmission.cs b/src/ScriptCs.Core/ISubmission.cs new file mode 100644 index 00000000..a92fc52d --- /dev/null +++ b/src/ScriptCs.Core/ISubmission.cs @@ -0,0 +1,7 @@ +namespace ScriptCs +{ + public interface ISubmission + { + ICompilation Compilation { get; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index c7b2bfee..9b1028b8 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -42,6 +42,7 @@ + @@ -65,8 +66,11 @@ + + + diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 90d0f2cf..43620db6 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -7,7 +7,7 @@ namespace ScriptCs { public class ScriptExecutor : IScriptExecutor { - private readonly IFileSystem _fileSystem; + protected readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; private readonly IScriptEngine _scriptEngine; private readonly IScriptHostFactory _scriptHostFactory; @@ -43,15 +43,15 @@ public void Execute(string script, IEnumerable paths, IEnumerable PrepareBinFolder(IEnumerable paths, string bin) diff --git a/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs b/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs new file mode 100644 index 00000000..b719a57e --- /dev/null +++ b/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs @@ -0,0 +1,21 @@ +using Roslyn.Compilers.Common; + +namespace ScriptCs.Wrappers +{ + using System.IO; + + public class CompilationWrapper : ICompilation + { + private readonly CommonCompilation _compilation; + + public CompilationWrapper(CommonCompilation compilation) + { + this._compilation = compilation; + } + + public CommonEmitResult Emit(Stream outputStream, Stream pdbStream) + { + return this._compilation.Emit(outputStream, pdbStream: pdbStream); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs index e928c8e9..132505fb 100644 --- a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs @@ -1,15 +1,16 @@ -using Roslyn.Scripting; -using Roslyn.Scripting.CSharp; +using Roslyn.Scripting.CSharp; namespace ScriptCs.Wrappers { + using Roslyn.Scripting; + internal class ScriptEngineWrapper : IScriptEngine { - private ScriptEngine scriptEngine; + private CommonScriptEngine scriptEngine; - public ScriptEngineWrapper() + public ScriptEngineWrapper(CommonScriptEngine engine = null) { - this.scriptEngine = new ScriptEngine(); + this.scriptEngine = engine ?? new ScriptEngine(); } public string BaseDirectory diff --git a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs index 23a09331..24a0fe9e 100644 --- a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs @@ -11,6 +11,14 @@ public SessionWrapper(Session session) this._session = session; } + public IScriptEngine Engine + { + get + { + return new ScriptEngineWrapper(this._session.Engine); + } + } + public object Execute(string code) { return this._session.Execute(code); @@ -25,5 +33,11 @@ public void ImportNamespace(string @namespace) { this._session.ImportNamespace(@namespace); } + + public ISubmission CompileSubmission(string code) + { + var submission = this._session.CompileSubmission(code); + return new SubmissionWrapper(submission); + } } } diff --git a/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs b/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs new file mode 100644 index 00000000..fdf17e4f --- /dev/null +++ b/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs @@ -0,0 +1,26 @@ +using Roslyn.Scripting; + +namespace ScriptCs.Wrappers +{ + using System.Threading; + + using Roslyn.Compilers; + + public class SubmissionWrapper : ISubmission + { + private readonly Submission _submission; + + public SubmissionWrapper(Submission submission) + { + this._submission = submission; + } + + public ICompilation Compilation + { + get + { + return new CompilationWrapper(this._submission.Compilation); + } + } + } +} diff --git a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs index ee18920d..84d90e92 100644 --- a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs @@ -1,18 +1,28 @@ -using Moq; +using System; +using System.IO; +using System.Linq; +using Moq; +using ScriptCs.Contracts; +using Xunit; namespace ScriptCs.Tests { - using Xunit; public class DebugScriptExecutorTests { - public static ScriptExecutor CreateScriptExecutor( + public static DebugScriptExecutor CreateScriptExecutor( Mock fileSystem = null, Mock fileProcessor = null, Mock scriptEngine = null, Mock scriptHostFactory = null) { - fileSystem = fileSystem ?? new Mock(); + if (fileSystem == null) + { + fileSystem = new Mock(); + fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(@"C:\"); + fileSystem.Setup(fs => fs.CreateFileStream(It.IsAny(), It.IsAny())) + .Returns(new MemoryStream()); + } fileProcessor = fileProcessor ?? new Mock(); @@ -30,18 +40,92 @@ public static ScriptExecutor CreateScriptExecutor( if (scriptHostFactory == null) { - return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); + return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); + } + else + { + return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, scriptHostFactory.Object); } - - return new ScriptExecutor( - fileSystem.Object, fileProcessor.Object, scriptEngine.Object, scriptHostFactory.Object); } public class TheExecuteMethod { - [Fact(Skip = "No code yet")] - public void ShouldAddSystemDiagnosticsUsingAutomaticallyWhenDebugging() + [Fact] + public void ShouldCompileProcessedCode() { + // arrange + var filePreProcessor = new Mock(); + var scriptEngine = new Mock(); + var session = new Mock(); + var submission = new Mock>(); + var compilation = new Mock(); + + const string PathToScript = @"C:\script.csx"; + var code = Guid.NewGuid().ToString(); + + filePreProcessor.Setup(p => p.ProcessFile(PathToScript)).Returns(code); + + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); + scriptEngine.SetupProperty(e => e.BaseDirectory); + + session.Setup(s => s.CompileSubmission(code)).Returns(submission.Object).Verifiable(); + session.Setup(s => s.Engine).Returns(scriptEngine.Object); + + submission.Setup(s => s.Compilation).Returns(compilation.Object); + + var scriptExecutor = DebugScriptExecutorTests.CreateScriptExecutor( + scriptEngine: scriptEngine, + fileProcessor: filePreProcessor); + + // act + scriptExecutor.Execute(PathToScript, Enumerable.Empty(), Enumerable.Empty()); + + // assert + session.Verify(s => s.CompileSubmission(code), Times.Once()); + } + + [Fact] + public void ShouldEmitCompilationProvidingPathsForDllAndPdbFiles() + { + // arrange + var scriptEngine = new Mock(); + var session = new Mock(); + var submission = new Mock>(); + var compilation = new Mock(); + + var fileSystem = new Mock(); + + const string PathToScript = @"C:\script.csx"; + const string BinDir = @"C:\bin"; + const string OutputDllName = "script.dll"; + const string OutputPdbName = "script.pdb"; + var pdbFullPath = Path.Combine(BinDir, OutputPdbName); + var dllFullPath = Path.Combine(BinDir, OutputDllName); + + var pdbStream = new MemoryStream(); + var dllStream = new MemoryStream(); + + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); + scriptEngine.SetupProperty(e => e.BaseDirectory); + + session.Setup(s => s.CompileSubmission(It.IsAny())).Returns(submission.Object); + session.Setup(s => s.Engine).Returns(scriptEngine.Object); + + submission.Setup(s => s.Compilation).Returns(compilation.Object); + + fileSystem.Setup(fs => fs.GetWorkingDirectory(PathToScript)).Returns(@"C:\"); + fileSystem.Setup(fs => fs.CreateFileStream(pdbFullPath, FileMode.OpenOrCreate)).Returns(pdbStream).Verifiable(); + fileSystem.Setup(fs => fs.CreateFileStream(dllFullPath, FileMode.OpenOrCreate)).Returns(dllStream).Verifiable(); + + compilation.Setup(c => c.Emit(dllStream, pdbStream)).Verifiable(); + + var scriptExecutor = DebugScriptExecutorTests.CreateScriptExecutor(fileSystem, scriptEngine: scriptEngine); + + // act + scriptExecutor.Execute(PathToScript, Enumerable.Empty(), Enumerable.Empty()); + + // assert + compilation.Verify(c => c.Emit(dllStream, pdbStream), Times.Once()); } } } diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 9f28e7d7..214060b9 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -16,6 +16,7 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + ..\..\packages\Should.1.1.12.0\lib\Should.dll diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index a0f48688..8fa6fb07 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -18,7 +18,11 @@ public static ScriptExecutor CreateScriptExecutor( Mock scriptEngine = null, Mock scriptHostFactory = null) { - fileSystem = fileSystem ?? new Mock(); + if (fileSystem == null) + { + fileSystem = new Mock(); + fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(@"C:\"); + } fileProcessor = fileProcessor ?? new Mock(); @@ -309,7 +313,6 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn fileSystem.Setup(fs => fs.GetWorkingDirectory(scriptName)).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); @@ -343,7 +346,6 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi fileSystem.Setup(fs => fs.GetWorkingDirectory(scriptName)).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); @@ -386,7 +388,6 @@ public void ShouldAddReferenceToEachDestinationFile() fileSystem.Setup(fs => fs.GetWorkingDirectory(scriptName)).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); session.Setup(e => e.AddReference(destinationFilePath1)).Verifiable(); session.Setup(e => e.AddReference(destinationFilePath2)).Verifiable(); From df36878411489511bf2240263feedb6df3e81a32 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 10 Mar 2013 14:43:16 -0300 Subject: [PATCH 0050/1224] # Updated exports to have different components for debug and run --- src/ScriptCs.Core/Constants.cs | 3 +++ src/ScriptCs.Core/DebugFilePreProcessor.cs | 2 ++ src/ScriptCs.Core/DebugScriptExecutor.cs | 6 ++++-- src/ScriptCs.Core/FilePreProcessor.cs | 3 +-- src/ScriptCs.Core/IFilePreProcessor.cs | 1 - src/ScriptCs.Core/IScriptExecutor.cs | 2 -- src/ScriptCs.Core/ScriptExecutor.cs | 3 ++- .../Wrappers/ScriptEngineWrapper.cs | 16 +++++++++++----- src/ScriptCs/Program.cs | 8 ++------ 9 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/ScriptCs.Core/Constants.cs b/src/ScriptCs.Core/Constants.cs index e9aa95f7..28bb1585 100644 --- a/src/ScriptCs.Core/Constants.cs +++ b/src/ScriptCs.Core/Constants.cs @@ -4,5 +4,8 @@ public static class Constants { public const string PackagesFile = "packages.config"; public const string PackagesFolder = "packages"; + + public const string DebugContractName = "Debug"; + public const string RunContractName = "Run"; } } diff --git a/src/ScriptCs.Core/DebugFilePreProcessor.cs b/src/ScriptCs.Core/DebugFilePreProcessor.cs index 7a3ac7b3..ff133bb5 100644 --- a/src/ScriptCs.Core/DebugFilePreProcessor.cs +++ b/src/ScriptCs.Core/DebugFilePreProcessor.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; +using System.ComponentModel.Composition; using System.Linq; namespace ScriptCs { + [Export(Constants.DebugContractName, typeof(IFilePreProcessor))] public class DebugFilePreProcessor : FilePreProcessor { private const string SystemDiagnosticsUsing = "using System.Diagnostics;"; diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index 7ed3929d..9120f2bd 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -1,13 +1,15 @@ namespace ScriptCs { - using System; + using System.ComponentModel.Composition; using System.IO; using Roslyn.Compilers.Common; + [Export(Constants.DebugContractName, typeof(IScriptExecutor))] public class DebugScriptExecutor : ScriptExecutor { - public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) + [ImportingConstructor] + public DebugScriptExecutor(IFileSystem fileSystem, [Import(Constants.DebugContractName)]IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) : base(fileSystem, filePreProcessor, scriptEngine, scriptHostFactory) { } diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 353cb88d..975342f5 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; -using System.Diagnostics; -using System.IO; using System.Linq; namespace ScriptCs { + [Export(Constants.RunContractName, typeof(IFilePreProcessor))] public class FilePreProcessor : IFilePreProcessor { private const string LoadString = "#load "; diff --git a/src/ScriptCs.Core/IFilePreProcessor.cs b/src/ScriptCs.Core/IFilePreProcessor.cs index 71583d11..40130b45 100644 --- a/src/ScriptCs.Core/IFilePreProcessor.cs +++ b/src/ScriptCs.Core/IFilePreProcessor.cs @@ -2,7 +2,6 @@ namespace ScriptCs { - [InheritedExport] public interface IFilePreProcessor { string ProcessFile(string path); diff --git a/src/ScriptCs.Core/IScriptExecutor.cs b/src/ScriptCs.Core/IScriptExecutor.cs index 5b455302..07ca8b8f 100644 --- a/src/ScriptCs.Core/IScriptExecutor.cs +++ b/src/ScriptCs.Core/IScriptExecutor.cs @@ -1,10 +1,8 @@ using ScriptCs.Contracts; using System.Collections.Generic; -using System.ComponentModel.Composition; namespace ScriptCs { - [InheritedExport] public interface IScriptExecutor { void Execute(string script, IEnumerable paths, IEnumerable recipes); diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 43620db6..188cb22e 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -5,6 +5,7 @@ namespace ScriptCs { + [Export(Constants.RunContractName, typeof(IScriptExecutor))] public class ScriptExecutor : IScriptExecutor { protected readonly IFileSystem _fileSystem; @@ -13,7 +14,7 @@ public class ScriptExecutor : IScriptExecutor private readonly IScriptHostFactory _scriptHostFactory; [ImportingConstructor] - public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) + public ScriptExecutor(IFileSystem fileSystem, [Import(Constants.RunContractName)]IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) { _fileSystem = fileSystem; _filePreProcessor = filePreProcessor; diff --git a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs index 132505fb..57c6c347 100644 --- a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs @@ -1,16 +1,22 @@ -using Roslyn.Scripting.CSharp; +using System.ComponentModel.Composition; +using Roslyn.Scripting; +using Roslyn.Scripting.CSharp; namespace ScriptCs.Wrappers { - using Roslyn.Scripting; - internal class ScriptEngineWrapper : IScriptEngine { private CommonScriptEngine scriptEngine; - public ScriptEngineWrapper(CommonScriptEngine engine = null) + [ImportingConstructor] + public ScriptEngineWrapper() + { + this.scriptEngine = new ScriptEngine(); + } + + public ScriptEngineWrapper(CommonScriptEngine engine) { - this.scriptEngine = engine ?? new ScriptEngine(); + this.scriptEngine = engine; } public string BaseDirectory diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 5b6e69ed..2080ce22 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; using System.ComponentModel.Composition.Hosting; -using System.IO; using System.Linq; using ScriptCs.Exceptions; -using ScriptCs.Package; namespace ScriptCs { @@ -22,10 +19,8 @@ private static void Main(string[] args) var container = ConfigureMef(); var fileSystem = container.GetExportedValue(); - var packageContainer = container.GetExportedValue(); var resolver = container.GetExportedValue(); - - var executor = container.GetExportedValue(); + var executor = container.GetExportedValue(Constants.RunContractName); var scriptPackManager = new ScriptPackResolver(container); try @@ -36,6 +31,7 @@ private static void Main(string[] args) { Console.WriteLine("Found assembly reference: " + path); } + executor.Execute(script, paths, scriptPackManager.GetPacks()); } catch (MissingAssemblyException ex) From 19a772f62fa2cb58b311612c8ca6d286026305dd Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 10 Mar 2013 16:22:22 -0300 Subject: [PATCH 0051/1224] # Added support for compilation failures --- src/ScriptCs.Core/CompilationResult.cs | 27 ++++++++++ src/ScriptCs.Core/DebugScriptExecutor.cs | 13 ++++- .../Exceptions/CompilationException.cs | 11 ++++ src/ScriptCs.Core/ICompilation.cs | 3 +- src/ScriptCs.Core/ICompilationResult.cs | 8 +++ src/ScriptCs.Core/ScriptCs.Core.csproj | 3 ++ .../Wrappers/CompilationWrapper.cs | 5 +- .../DebugScriptExecutorTests.cs | 50 ++++++++++++++++++- .../ScriptExecutorTests.cs | 2 +- 9 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 src/ScriptCs.Core/CompilationResult.cs create mode 100644 src/ScriptCs.Core/Exceptions/CompilationException.cs create mode 100644 src/ScriptCs.Core/ICompilationResult.cs diff --git a/src/ScriptCs.Core/CompilationResult.cs b/src/ScriptCs.Core/CompilationResult.cs new file mode 100644 index 00000000..2603f123 --- /dev/null +++ b/src/ScriptCs.Core/CompilationResult.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Linq; +using Roslyn.Compilers.Common; + +namespace ScriptCs +{ + using System; + + public class CompilationResult : ICompilationResult + { + public CompilationResult(CommonEmitResult emitResult) + { + this.Success = emitResult.Success; + + this.ErrorMessage = this.RetrieveErrorMessage(emitResult.Diagnostics); + } + + public bool Success { get; private set; } + + public string ErrorMessage { get; private set; } + + private string RetrieveErrorMessage(IEnumerable diagnostics) + { + return string.Join(Environment.NewLine, diagnostics.Select(d => d.ToString())); + } + } +} diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index 9120f2bd..34413196 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -5,6 +5,8 @@ using Roslyn.Compilers.Common; + using ScriptCs.Exceptions; + [Export(Constants.DebugContractName, typeof(IScriptExecutor))] public class DebugScriptExecutor : ScriptExecutor { @@ -30,13 +32,22 @@ protected override void Execute(string absolutePathToScript, ISession session, s ISubmission submission = session.CompileSubmission(code); - CommonEmitResult result; + ICompilationResult result; using (Stream outputStream = _fileSystem.CreateFileStream(outputPath, FileMode.OpenOrCreate)) using (Stream pdbStream = _fileSystem.CreateFileStream(pdbPath, FileMode.OpenOrCreate)) { result = submission.Compilation.Emit(outputStream, pdbStream); } + + if (result.Success) + { + + } + else + { + throw new CompilationException(result.ErrorMessage); + } } } } diff --git a/src/ScriptCs.Core/Exceptions/CompilationException.cs b/src/ScriptCs.Core/Exceptions/CompilationException.cs new file mode 100644 index 00000000..b239a55c --- /dev/null +++ b/src/ScriptCs.Core/Exceptions/CompilationException.cs @@ -0,0 +1,11 @@ +using System; + +namespace ScriptCs.Exceptions +{ + public class CompilationException : Exception + { + public CompilationException(string message) : base(message) + { + } + } +} diff --git a/src/ScriptCs.Core/ICompilation.cs b/src/ScriptCs.Core/ICompilation.cs index febf3aac..383e5c87 100644 --- a/src/ScriptCs.Core/ICompilation.cs +++ b/src/ScriptCs.Core/ICompilation.cs @@ -1,10 +1,9 @@ using System.IO; -using Roslyn.Compilers.Common; namespace ScriptCs { public interface ICompilation { - CommonEmitResult Emit(Stream outputStream, Stream pdbStream); + ICompilationResult Emit(Stream outputStream, Stream pdbStream); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ICompilationResult.cs b/src/ScriptCs.Core/ICompilationResult.cs new file mode 100644 index 00000000..991989d4 --- /dev/null +++ b/src/ScriptCs.Core/ICompilationResult.cs @@ -0,0 +1,8 @@ +namespace ScriptCs +{ + public interface ICompilationResult + { + bool Success { get; } + string ErrorMessage { get; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 9b1028b8..4ea8c8e0 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -31,8 +31,10 @@ + + Properties\CommonAssemblyInfo.cs @@ -43,6 +45,7 @@ + diff --git a/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs b/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs index b719a57e..d0d10040 100644 --- a/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs @@ -13,9 +13,10 @@ public CompilationWrapper(CommonCompilation compilation) this._compilation = compilation; } - public CommonEmitResult Emit(Stream outputStream, Stream pdbStream) + public ICompilationResult Emit(Stream outputStream, Stream pdbStream) { - return this._compilation.Emit(outputStream, pdbStream: pdbStream); + var emitResult = this._compilation.Emit(outputStream, pdbStream: pdbStream); + return new CompilationResult(emitResult); } } } \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs index 84d90e92..99660841 100644 --- a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs @@ -3,10 +3,12 @@ using System.Linq; using Moq; using ScriptCs.Contracts; +using Should; using Xunit; namespace ScriptCs.Tests { + using ScriptCs.Exceptions; public class DebugScriptExecutorTests { @@ -59,10 +61,13 @@ public void ShouldCompileProcessedCode() var session = new Mock(); var submission = new Mock>(); var compilation = new Mock(); + var compilationResult = new Mock(); const string PathToScript = @"C:\script.csx"; var code = Guid.NewGuid().ToString(); + compilationResult.Setup(r => r.Success).Returns(true); + filePreProcessor.Setup(p => p.ProcessFile(PathToScript)).Returns(code); scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); @@ -73,6 +78,8 @@ public void ShouldCompileProcessedCode() submission.Setup(s => s.Compilation).Returns(compilation.Object); + compilation.Setup(c => c.Emit(It.IsAny(), It.IsAny())).Returns(compilationResult.Object).Verifiable(); + var scriptExecutor = DebugScriptExecutorTests.CreateScriptExecutor( scriptEngine: scriptEngine, fileProcessor: filePreProcessor); @@ -92,6 +99,7 @@ public void ShouldEmitCompilationProvidingPathsForDllAndPdbFiles() var session = new Mock(); var submission = new Mock>(); var compilation = new Mock(); + var compilationResult = new Mock(); var fileSystem = new Mock(); @@ -105,6 +113,8 @@ public void ShouldEmitCompilationProvidingPathsForDllAndPdbFiles() var pdbStream = new MemoryStream(); var dllStream = new MemoryStream(); + compilationResult.Setup(r => r.Success).Returns(true); + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); scriptEngine.SetupProperty(e => e.BaseDirectory); @@ -117,7 +127,7 @@ public void ShouldEmitCompilationProvidingPathsForDllAndPdbFiles() fileSystem.Setup(fs => fs.CreateFileStream(pdbFullPath, FileMode.OpenOrCreate)).Returns(pdbStream).Verifiable(); fileSystem.Setup(fs => fs.CreateFileStream(dllFullPath, FileMode.OpenOrCreate)).Returns(dllStream).Verifiable(); - compilation.Setup(c => c.Emit(dllStream, pdbStream)).Verifiable(); + compilation.Setup(c => c.Emit(dllStream, pdbStream)).Returns(compilationResult.Object).Verifiable(); var scriptExecutor = DebugScriptExecutorTests.CreateScriptExecutor(fileSystem, scriptEngine: scriptEngine); @@ -127,6 +137,44 @@ public void ShouldEmitCompilationProvidingPathsForDllAndPdbFiles() // assert compilation.Verify(c => c.Emit(dllStream, pdbStream), Times.Once()); } + + [Fact] + public void ShouldThrowCompilationExceptionIfCompilationFails() + { + // arrange + var scriptEngine = new Mock(); + var session = new Mock(); + var submission = new Mock>(); + var compilation = new Mock(); + var compilationResult = new Mock(); + + const string ErrorMessage = "Error message"; + compilationResult.Setup(r => r.Success).Returns(false).Verifiable(); + compilationResult.Setup(r => r.ErrorMessage).Returns(ErrorMessage).Verifiable(); + + const string PathToScript = @"C:\script.csx"; + + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); + scriptEngine.SetupProperty(e => e.BaseDirectory); + + session.Setup(s => s.CompileSubmission(It.IsAny())).Returns(submission.Object); + session.Setup(s => s.Engine).Returns(scriptEngine.Object); + + submission.Setup(s => s.Compilation).Returns(compilation.Object); + + compilation.Setup(c => c.Emit(It.IsAny(), It.IsAny())).Returns(compilationResult.Object).Verifiable(); + + var scriptExecutor = DebugScriptExecutorTests.CreateScriptExecutor(scriptEngine: scriptEngine); + + // act + assert + var exception = Assert.Throws(() => + scriptExecutor.Execute(PathToScript, Enumerable.Empty(), Enumerable.Empty())); + + exception.Message.ShouldEqual(ErrorMessage); + + compilationResult.Verify(r => r.ErrorMessage, Times.Once()); + compilationResult.Verify(r => r.Success, Times.Once()); + } } } } diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 8fa6fb07..047a9fe4 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -370,7 +370,7 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); + var scriptExecutor = CreateScriptExecutor(fileSystem, scriptEngine: scriptEngine); var currentDirectory = @"C:\"; var sourceFilePath1 = Path.Combine(@"C:\fileDir", "fileName1.cs"); From a70a81bbb49bcfe6022de950591e8a2baf1b75a9 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 10 Mar 2013 16:44:19 -0300 Subject: [PATCH 0052/1224] # Support to run generated assembly with debug capabilities --- .../ConsoleCompiledDllDebugger.cs | 27 ++++++++++ src/ScriptCs.Core/DebugScriptExecutor.cs | 33 ++++++++----- src/ScriptCs.Core/ICompiledDllDebugger.cs | 10 ++++ src/ScriptCs.Core/ISession.cs | 5 +- src/ScriptCs.Core/ScriptCs.Core.csproj | 2 + src/ScriptCs.Core/Wrappers/SessionWrapper.cs | 8 +++ .../DebugScriptExecutorTests.cs | 49 +++++++++++++++++-- 7 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 src/ScriptCs.Core/ConsoleCompiledDllDebugger.cs create mode 100644 src/ScriptCs.Core/ICompiledDllDebugger.cs diff --git a/src/ScriptCs.Core/ConsoleCompiledDllDebugger.cs b/src/ScriptCs.Core/ConsoleCompiledDllDebugger.cs new file mode 100644 index 00000000..3de35654 --- /dev/null +++ b/src/ScriptCs.Core/ConsoleCompiledDllDebugger.cs @@ -0,0 +1,27 @@ +using System; +using System.Diagnostics; +using System.Reflection; + +namespace ScriptCs +{ + public class ConsoleCompiledDllDebugger : ICompiledDllDebugger + { + private const string CompiledScriptClass = "Submission#0"; + private const string CompiledScriptMethod = ""; + private const string AttachMessageTemplate = + "Attach to process {0} and press ENTER. Then use the 'go' command in the debugger."; + + public void Run(string dllPath, ISession session) + { + var assembly = Assembly.LoadFrom(dllPath); + var type = assembly.GetType(CompiledScriptClass); + var method = type.GetMethod(CompiledScriptMethod, BindingFlags.Static | BindingFlags.Public); + + var pid = Process.GetCurrentProcess().Id; + Console.WriteLine(AttachMessageTemplate, pid); + Console.ReadLine(); + + method.Invoke(null, new[] { session.WrappedSession }); + } + } +} diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index 34413196..ea79cf1b 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -1,23 +1,32 @@ -namespace ScriptCs -{ - using System.ComponentModel.Composition; - using System.IO; - - using Roslyn.Compilers.Common; - - using ScriptCs.Exceptions; +using System.ComponentModel.Composition; +using System.IO; +using ScriptCs.Exceptions; +namespace ScriptCs +{ [Export(Constants.DebugContractName, typeof(IScriptExecutor))] public class DebugScriptExecutor : ScriptExecutor { + private readonly ICompiledDllDebugger compiledDllDebugger; + [ImportingConstructor] - public DebugScriptExecutor(IFileSystem fileSystem, [Import(Constants.DebugContractName)]IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) + public DebugScriptExecutor( + IFileSystem fileSystem, + [Import(Constants.DebugContractName)]IFilePreProcessor filePreProcessor, + IScriptEngine scriptEngine, + ICompiledDllDebugger compiledDllDebugger, + IScriptHostFactory scriptHostFactory) : base(fileSystem, filePreProcessor, scriptEngine, scriptHostFactory) { + this.compiledDllDebugger = compiledDllDebugger; } - public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) - : base(fileSystem, filePreProcessor, scriptEngine) + public DebugScriptExecutor( + IFileSystem fileSystem, + IFilePreProcessor filePreProcessor, + IScriptEngine scriptEngine, + ICompiledDllDebugger compiledDllDebugger) + : this(fileSystem, filePreProcessor, scriptEngine, compiledDllDebugger, new ScriptHostFactory()) { } @@ -42,7 +51,7 @@ protected override void Execute(string absolutePathToScript, ISession session, s if (result.Success) { - + this.compiledDllDebugger.Run(outputPath, session); } else { diff --git a/src/ScriptCs.Core/ICompiledDllDebugger.cs b/src/ScriptCs.Core/ICompiledDllDebugger.cs new file mode 100644 index 00000000..f944d5ec --- /dev/null +++ b/src/ScriptCs.Core/ICompiledDllDebugger.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.Composition; + +namespace ScriptCs +{ + [InheritedExport] + public interface ICompiledDllDebugger + { + void Run(string dllPath, ISession session); + } +} diff --git a/src/ScriptCs.Core/ISession.cs b/src/ScriptCs.Core/ISession.cs index 5abcd9ae..70ad8675 100644 --- a/src/ScriptCs.Core/ISession.cs +++ b/src/ScriptCs.Core/ISession.cs @@ -1,8 +1,11 @@ -namespace ScriptCs +using Roslyn.Scripting; + +namespace ScriptCs { public interface ISession { IScriptEngine Engine { get; } + Session WrappedSession { get; } object Execute(string code); void AddReference(string assemblyDisplayNameOrPath); void ImportNamespace(string @namespace); diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 4ea8c8e0..987118cc 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -32,6 +32,7 @@ + @@ -46,6 +47,7 @@ + diff --git a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs index 24a0fe9e..c5408803 100644 --- a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs @@ -19,6 +19,14 @@ public IScriptEngine Engine } } + public Session WrappedSession + { + get + { + return this._session; + } + } + public object Execute(string code) { return this._session.Execute(code); diff --git a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs index 99660841..44d631d1 100644 --- a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs @@ -16,7 +16,8 @@ public static DebugScriptExecutor CreateScriptExecutor( Mock fileSystem = null, Mock fileProcessor = null, Mock scriptEngine = null, - Mock scriptHostFactory = null) + Mock scriptHostFactory = null, + Mock compiledDllDebugger = null) { if (fileSystem == null) { @@ -40,13 +41,15 @@ public static DebugScriptExecutor CreateScriptExecutor( scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(mockSession.Object); } + compiledDllDebugger = compiledDllDebugger ?? new Mock(); + if (scriptHostFactory == null) { - return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); + return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, compiledDllDebugger.Object); } else { - return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, scriptHostFactory.Object); + return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, compiledDllDebugger.Object, scriptHostFactory.Object); } } @@ -175,6 +178,46 @@ public void ShouldThrowCompilationExceptionIfCompilationFails() compilationResult.Verify(r => r.ErrorMessage, Times.Once()); compilationResult.Verify(r => r.Success, Times.Once()); } + + [Fact] + public void ShouldRunCompileAssemblyRunnerOnOutputPathIfCompilationSucceeds() + { + // arrange + var scriptEngine = new Mock(); + var session = new Mock(); + var submission = new Mock>(); + var compilation = new Mock(); + var compilationResult = new Mock(); + var compiledDllDebugger = new Mock(); + + compilationResult.Setup(r => r.Success).Returns(true).Verifiable(); + + const string PathToScript = @"C:\script.csx"; + const string BinDir = @"C:\bin"; + const string OutputDllName = "script.dll"; + var dllFullPath = Path.Combine(BinDir, OutputDllName); + + scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); + scriptEngine.SetupProperty(e => e.BaseDirectory); + + session.Setup(s => s.CompileSubmission(It.IsAny())).Returns(submission.Object); + session.Setup(s => s.Engine).Returns(scriptEngine.Object); + + submission.Setup(s => s.Compilation).Returns(compilation.Object); + + compilation.Setup(c => c.Emit(It.IsAny(), It.IsAny())).Returns(compilationResult.Object).Verifiable(); + + compiledDllDebugger.Setup(r => r.Run(dllFullPath, session.Object)).Verifiable(); + + var scriptExecutor = DebugScriptExecutorTests.CreateScriptExecutor(scriptEngine: scriptEngine, compiledDllDebugger: compiledDllDebugger); + + // act + scriptExecutor.Execute(PathToScript, Enumerable.Empty(), Enumerable.Empty()); + + // assert + compilationResult.Verify(r => r.Success, Times.Once()); + compiledDllDebugger.Verify(r => r.Run(dllFullPath, session.Object), Times.Once()); + } } } } From 93568ab7f7773a38a4854756c80b1a4fbf8d1d00 Mon Sep 17 00:00:00 2001 From: Andreas Hakansson Date: Sat, 9 Mar 2013 23:36:43 +0100 Subject: [PATCH 0053/1224] Added NancyFX sample Split up the sample in multiple files Fixed the final bits of the demo --- samples/nancy/NuGet.exe | Bin 0 -> 651264 bytes samples/nancy/README.md | 23 +++++++++ samples/nancy/bootstrapper.csx | 25 ++++++++++ .../nancy/customroutedescriptionprovider.csx | 7 +++ samples/nancy/module.csx | 9 ++++ samples/nancy/packages.config | 7 +++ samples/nancy/pathprovider.csx | 7 +++ samples/nancy/start.csx | 27 +++++++++++ samples/nancy/views/index.html | 45 ++++++++++++++++++ src/Scriptcs.sln | 39 +++++++++++++++ 10 files changed, 189 insertions(+) create mode 100644 samples/nancy/NuGet.exe create mode 100644 samples/nancy/README.md create mode 100644 samples/nancy/bootstrapper.csx create mode 100644 samples/nancy/customroutedescriptionprovider.csx create mode 100644 samples/nancy/module.csx create mode 100644 samples/nancy/packages.config create mode 100644 samples/nancy/pathprovider.csx create mode 100644 samples/nancy/start.csx create mode 100644 samples/nancy/views/index.html create mode 100644 src/Scriptcs.sln diff --git a/samples/nancy/NuGet.exe b/samples/nancy/NuGet.exe new file mode 100644 index 0000000000000000000000000000000000000000..4645f4b35e8ebd8508fe5691df73ce88a4a8028a GIT binary patch literal 651264 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 z zWl!ZRuNBIdXZ*Gnky@UG*FrzP`XZd-RaYemTe#{|?9O1IlUBl4Bf~E=l0S>+Uk?vo zx`*|`5XP(RQU#6$AGOb=OxJ|l|8$&d%pzPKwJw)XjMD1*lvz_K&K741#hG!4@I^=& z1^NuMQ_IW|a2>E>CQ6j~i>TcwAUiCr@!A8q39~Sq8TVX8=6RW}_wcogZ zisQ+%lcj17J)-s~l#A6IG;pm5g>kV|%atdnH^jGuooFFsCS^LHTwn`eHMdL(j9s0+ z2%Q?~L&#c-XoBc~P${?8->Pm{2$;Cb_F&?4kF9V-owq_=#L9>w^kUgAQS1Q0=_p-V zL{7&mpP8E(naNLGt(IIxESVF8*{*0s+t^76*sIRIfq`J#emW7vV^I*HS<%{a>A^FJ zPE5BSc;~L%!ddbiwaD^ zXMZ9!Hb)@bP6Nd{_Gv|f(?WtkG`2KO_h+%OJ7peKSL0X_9<^F&-0FTVRIqS*14jNb zw~>}c_rc}X|Mvv_^?5FQh6bKGQGT&pJD#tNPwGC=6hxjqeT5EU`zpTlIrVZecNv7p z)yg?IKx(C#xgwT7m-3au6gEYu!}2p%bHz%fT*+N7=AgH*^$Z&2idSmlbC|hA1t=>0 zHp`&9q)GkXM>>pE1$Jllpu;$U^wcN}94_RrcdLiGp3h?+N6&MO%}q>{uC(^~Sq^p% ziaS4(8~y5Bv2rzkaSBQsE4_ z<7FI1(^Y4wItgxh5l3n!y&g zBV>Fp6%t4PC&Y=yV)R;z_R3V5bkH|HALAb#4U@r~+F zOOF;-TiJuJ4X4c77xLAbiuA(ju+9dQ9xbd56Jl6CB+>gLo$t9b_5U-%XHd&<3W;ny z0H;u;bUM%V7N)Qj77&&=1gd93=^75tex`>Wi;K!{KvWjWoR@P|$N|WLbCszawq__H zYm*R4xr=D9fK>ptVkk;4?afuoxl(O6nw!pF&2i4amxcZm z;Lyqyq5iG{FLk02M+nIh4jVx!vOul;FybU!^AOSKGklijq0fd&e3VJkD<%LRHcEx) zJ-nEOI3|Sx`4!82i2Czufa1eTyk7^*9wJ`*bs(4E_!-TXVVwQijAjhc`xwn9*#CFA zDf~I{?bD>D6I5>Fd zsc=Cb`rq9hzB9#q;iZ|WtF3FDM`Z*tcojVuA?}^?r(S^907vDfO5ZA0CKLE&JAG+5 zWGB9~lULwnE{Zd)G|nBr1RvUCw{NE}z9A=L--SmC+-i%P<@l^Hodai2Z#hYSo4ttW zj!)2QwOyT;E~%;~*n=pJEG5+>>|Pv^FHPVI;;U|}k*W5`NFij!+YHhtf#8W?<8l;d zN90UPVKoR-D){U|{|wfv+#K|iVLovW#h7nBFjD3MQabETSqJE;63&s&TneeVHf2^R z%lkMI^`agw@{>PBjBi8UPZ6__mfS?Im1^9DuD`pOM}$tr!vllPBU0jp2e@M34=Kng zIqVwBDgPv2_=!<^YT*BcQ)X_QE{{2mX6|^Ui28EY3cI!=Glg?AmvOh59+NygC^&$d z!&xBshNf}B;8P?O*($HTNT02Qf@DOT&cJ+W$)ae&HDsu_A{<(H87Dy|st@g;_|Srb zRVsmfA6lyn-gSO@DhHRCNZfB>9Ozdc&(n)G35Pq}?sJur=cOew*fi%g#ZMoZPk|B~ z!xC6fIv?`BgnCnEi&bSW=y;8cb9aX)!~Ic(&v-3J?k?RtB%+W#tLl|0A6e=^domK7 z#Lf8V0+=TzaQ*(OTt16u3R!rlWGX*%X%1(6rgxNG|Hv+zb^+VG4b_e8iq2fK&v-Rj(|`fvN5h@1)9qLzeHWueYB zX08>*do#p<9v#U*2zNdqR_Qap0=eMqFp&y4j;3d%wk?Jk&P)1ZDWm%7;QHX%BxKnK z-`3|+i3ia>9nx+|nT_#Nap4&qs)ykG6lV6PgJbLzS0Jz+{7{8#aYvy~(I^Rz4&D*Q zzww2SE@oxj{uD=x5d4iNR;+`#P2-&=@OF7`PrFtN^|4@ESI@zCCpxiXTjQfeiQBU= zoE}ItkSqc{8haoOeg^b6XL519eB$IY=bl@Bm!4W|S$(^M2DfXX{(s>NW9Zx)D~@B? zSG(E||K33Vu)5k#6vwCX6}Y6-pLc4mMw9%EJ1tH3SAz5HqO&ba)6-g`FXx_~z(R9s zs!9{QfH%b8$HOr$xN~vhVH}q%c)c1X^1kvcPl6SAqN5_m!e+`imVp&N{+26v=i)bI zQs51V;Picb;Uj${$MBf{r)F4viUt&P%7bCh&BCBHJ#t9Dhh@{>6s}rsKe&Z=|Frhe znAR@mE>4xlamWe_;o_BIZUWb+;J$-PAXkzjtTj2HHIWB52pU=ccSnJGBSBU04MM!x ztLvE;vDt194#?VNbmkNeeikcZIFp{Q&EX(;t21J+Tg}jp!D;eZZUU#U=`V-<0v9@O z-e3zehm}&b8sPgd;qp)-^-vNhpwwpp%)bXm1Q83%0Us?GjRp0i$r6Ki{r)X%_C0eI z`{fh7KZ2cd+_-bM^B^_gjmYsl8qSXBrM^%EB%rkv%2NC{;Lj&zuYUsVd;(4UdJp(( z3DfK@*Je3Uv)nEZ4x~iZXnmh#TlaBPF5N#8^$3aN`0E|4VVCa919LB*NtshRq&N{c zRnFtG8m`=3#8YnY@$SvR)r+T1f@^zaSLpI&X&kqD^RMB`UOxBi+|2kI zuYUc0lJPJ+pUx%-3CBD7&ME-W@->B*v-t{CjT{ZeYk~Qzdwm<82l80*H)c!me)DGiJCPme zGsUTreX;!u*eb?%j-KMzptzG;zQ{AeRhVt?judlKcnb(ewX6J6Q>$BL5Hb^6%eir$ z#ALZVjv`*><$EZ5>s~=F)Q_In#0kuY2NR(&zP-}2#=J}8w@WM~=+lHPiCRK4cdhVu zgX;QVg40)WnkHAk-ap2m0NYGnJNZ-^jeXX{J4AHHPet^%JQZ=^<>GFzTdi`H9mV+r zoZ2n%VPaLyeD2s(oGacFh3=?pcUkz`_mjK&z+IK%KGl=?+%!#_D!yC7r>eaL-V{_xC0Cxg zOO*drR^t)G#aMT%u+U@vaT$VNb_Qm9bjE(_DdbN1hG4oUhp#mIB-ylSPkB;eMwLMCS)N7}VEKDfrBaSAG}& zLK{zX`UZjBaDq-B*) z-PAv5-}uA3@8Qi*T2tPOg#(Y>Q}w~emL}sp=VBaMI(N?pX12db^5?5ivls~R@9_C` zdUtqi>7J4P48Xto_2VbY0#x1)KwLcuamCx$oF$&P!ih9Ipbm4^`9b0Nyj$V*$@~bz1iNG!%jI!A8H0~T;L%`ThCdd3PRV_LsL#FD)As_l zwV%bUhWKiu-y2!k`lcFkuL^Ov?L*zcE8R2-JPtb@eqQhqsG7rrgHQ2WE_zn6I#M0O zRjAT<>&pGB^2!0$sMzqB#F0ciosFB>RsrghvXscdQ_R>Cfj!2)b4ir+bjm|Aq@SVj znaF=Q+@|SOnH8(D9qCo=_}P?RmCmf{&UU7|ySmcZb=mIBYKiv9??5Ws(=PFB4{Nor zLS!J7S-C1(UqJl%6|1@?S)hJBondODz^osz*ej`?^r{}F-D0#?YBhg}gl7LbB%sM` z{imsPnl(P)pAYe8{sP;t|7|LxWqLD&lU{AK)_OiV_N{#kSQq2(ut^W-=x?)vth7|y)e$xRy zFY$$T*Z4<*PUDpJd(tK^{M=!;@NCj{4-Jg1B_PV4=vTNOBa5`^j~=;n|~?2{VS04C(N4_3S%@IKVhi;j~LevZI|mG zI`*o6DD&~Jbt+2uEfnf%{vy>i-@z8aK8^D>&^*cjrhDUr<>%&6DG@+!oX9w$E#xo* z(UMNe?yQX?X)}OuUN1bsKaXR`vW+d-d7?ePz_I8|V?HnJm9gxa-^%X1!aqgg-((lx zvKY-@BjI+YF+1>oD=;t;nT(YToRgW1m0l>KaZ88!YmN@{*FwDefp_Cph_}X(WZM)8 z)Q~B2mMwC!H86%0YV&_&K{sy7yd|wrva5-S+SU9fN;Ib&F>AJHv*xg9)|@Ds-C{HU-p{dO^D1KO^8m75K{$&riODds{|kNycm5n&b{IEqQ4oM|t|4?U7^dM^ zcQua68w4@}f&=WU6?`4qFFnj%0WFlzI=B+vIq#l2RNH;$poQIPjoW`|%CL=pHhxkocGX#%E-Ca1T$deL-%^xHTg zZS=ab8U^_0*@nh4ZuUnK(}}5>02?0w+9VhJAqSK5y7`|N`Y~i|8^>oWhK{K}=b!)1 z!Iq&X6>scKZ#0ry{~>bc-?XgLIF?r73eZ6G1@;2}-|70{5|DSAJ#q06zi4tgs2NR1 z)w33M&~nCa`Ml&d-*KXT!6g72BK&*&b26AMuV)*tlL6=71sC6VUOGn-bf()VgPPyB z;&A@GsPMOA26QgSfC0KcirV1Z>~NF@;*4U&opdT8$Bq;Ln6~N~R}>31`K8KSloU*%{Q6 zy>W#E{BvegLo+)&KkW3DOeiraXcRR6f|;VEA@x;u`~u+S#kvr)p+I6IQ^ZYU7pAZ( zWQI0LBM3E*vJ`SNu2UaC@H%l$Wex>3|AEL95er)^9UEJmjb+7I*Np`m${#BRKQwDZ{C~3Xos@K25M40aEP#bckVCD;`S(OB&cDYz zm=)kwKQjxao_~)5f+h!tZWBsOu{wf|yg`DU;9e1w;zWut&f|`ZP`InskQjd$VU9rX z-)v`>DXZl#8tuCA6E><^48MPiQMu{lm!_hK3VKliooU3KA=B6d659a*FW9j{>il~i z*U*l>@iP`v@WITPm2PvGZw8{Lrh{em1Ui02X>(H*l33Zo@o77HT$4xw{;~{b7KTEb zqBO7xR8`Ugh@EWn0&r^ngJZ6@t^EtbuYNPo{oomkMljBG%F$~MZ7`V)D7GdId{q7a6%T7Y4 zjIPX{>d9o-BBNhj!6=J%Lf2$mDJEz4_P8j=@Kld1Wht6&Vp-MCJP2eJyY=^xG|YMb z7wj~|0O?o%9{$Wvk)581f|A^iSRUAA>s0*ppW~0LE9?J2e72$?&W`&3;GciupIiL% zKk=tQbD*)(vCLmO<8YxEgi1kZItabaW*Zbw&95_bn145UBxy^TMOV{D$IcT8r%yNuFa zONI8DEWdk^B=~;>)L8pE{>)#+a1;@!ze`wuY>5oT-o+vu{P`>VvyRbG{At8kORSoZ z>S+$ne2!cRZWR`$wBxF2p%;H{e4qL3!aTY4#(S78H-5tCkBA)Dy?KF(4>JjC75PQC zRY=bNDbeE`V-kW3Q3*{bq-f)HM|oX~G~UFB&U^ia8?605pFrO)$3! z30;3*S+zaAY6aUMNB`~<__HA0`Vm8aN&xIB=g@VI)Ae8SkIbzb-vP;2o0IEvD_x{fKqg9No8Ql@kusAEW^!rB{7E477P8*%bWst$*<2el>BNI-lO$Ai zNx%@&7Wo2oGPBxXv{1S;w-O9@%U0|#Db%I=kfVu#p~M!9>mLZl1^%snxCXuVNHc#y z%E(W4ewH=B`Z*8^szSnDT3~j)fprIV$N)A(QD%$5ase)|oox2+!OisNybV6zz+onz z!Y+}%bQ0nDS;xE>Ze<0Q*@R-NfI31QIRLyuB!msn6nIcLERzNewDES56h%k{R#GJE z9|Pe`1~iaTy_pO{Ay#N11H~jim_BGPBjNhT+V;(LT2t`>A|P--T({^t-7W1L-c9H^ zXH9#yy^Y`qE!z%82A^l!!T;@!|GT7dxYV+wHuHjE@YN9s3qWRO=!B1H-N zxmJe@Ow-t;0`~F6iibN89tfcKjniffKp$dmZQ- zdWO)tTpL1AO^l$f5}dt+V|FczLH$!#F$tk9xz%Wl{0G}o0yX%wuuhP9E`8L(X#kK` z7k=(~JAWrVR$Z%(~7* z!I)!|>Fu%k?+WP~f7R9aZ$htIWE@Di`SbV%;6eu6kje;i>(tC*wx%g8(;_U>fCc7C zQy_FTJ`h|RA2J_~aWG?h29gy5;p24%Ow#zctMQMhf$k#mVFwCeEs6w42slE-&G{?% zH_-ql;|Gdl{r$B$Od^i_$1-R6D@6W)KdB9{Epsv)7*vo4m?HquW+0+cLXlzgWF?{{ zaAPW4g79TOLBM{LN~JddPCA|00Et9qk+E4r#)B3ozp!YBG})2uK&+<+>I3z%9qnif zX*Sy3;p$Vqr%Adr%C+}ms)|seuqFo0NvYnWW4Z^)8AExwM}`Pdz(sc#vN;sTFuY4j z!0nTQD2M5QKM1ALJ)|(W(=lnCk{Hf>jsku9M)gbmCW%1WY(lR&buctcP%3_;!W_Ve z8OJ8uXcs=<409}5$Dm?NFcu_{?hTN__4k?Hc*~V*9(5u3iiL*o8YnTvr68@;-~#X50Y2F)wBpvp1}TNUy1fc5eVzrx1Hpi}B^ZEcZX98t0q4Xq8CVGkY{3P|K?Kq> zj9}pyMu0*XIgE(FJmCVYC@HKY0agG}(T@{gxOPrhEN_V8>l|Omw4+SNxTf1-x=2#< zO|oUSn*-Q53vCN-_)r*sp;RRJtESl-kN=uNTe@;{Zf!g!rhD(wrpEQ+rD<3kV?rbKw{?IGiQN=tetc zp<*E*jXJ03aqsR0RcuC*1I7kwm@hM!d1@*7FXNN`VA^$T<#jgMZ9e{;5bqQwziB#^MaoM z9=cBL1T*3S(UE;44m9_lz*sO)!KsX72}X(sN!?6(g%H?j6qRg%;Vu{cFTJ|1tbGCT zt_=<+fS3l>Y>4`xow^5V0mcO7IRY3TO-ctzX%#bt%qD=@Zgfe;{$d%q-Ep(ObDdlMXkSYt-;1Gr2Yj33}bax;{QKw?*V6Zb#0HITjv79FmvfTgEN9k z5R^egKu}OHVl+C62ntamC@Qu@BG%k8Gl(b3`JV3uN%G$N{C_(4-gVd6r|+}RKIMD4T?s5_s-@+KsrD+)@8dH0(leGs@p)UT z6rax*m*$I$FmP0et07_HSEEvhzbaq68U%{_ylTm_y{oMe=c5#u2(V7hspV|eL4z{_ zKIW@1%P=2uETKQ?u%cbKHbQutFb&HHe)rt}xxzHy+0!3`wp~l22QKp7xFH zg(0NT$1R&x%*Y=GMi#z&Q-q4$(5O-|PA$l6z6#^z%?hKq#mNEsc>>xVS!qElcQ*_t zj3?XUVk4=x!BInbN~5er#zFHjdi;qZ{92Sbd_`i|{ot$)iieAYlqT*aw({K32XsRs zW$bcpa3-0feX4~zR-^6N^j)D=lhaVEqqvNrFJ?{3Hec?rC>d#`b=~mZBC*eZEd!Rb&y=<$$ax48A$#Zn+z%;5X z4^J_(Vtd60RKZ!z;XnWBdu*ocZE+@6mvBY!DYu|Fle$yFjv0G_4baJ@XojZ|OTlMC z7~TkG7`%a$QfqXoGa-da<;#Qe9pLZ5wH%Z`3KZK6w+lD~(K!CD0qA^r9Qp}qK!@;0 zgzgxJF>LB>hZa^wG@o1_WEvrymdbf-b@Gjpn3On&%}^VbPw%O^Mc=gC)^V{kWj$LA ztq0pkcN^u>qynVNE?UL=IRjofScuW?)4#?t_XAEI5l+@|f`IqW0CjTEUSwDrEbYZH zwP~-ND^q)U#M)|KtuPwoHvQsI00~ZH=lexWah)__B8rbr!bFZdSJNlKK{6LW91WBx zU#%}Vl4e&x#K&*V$rdsSK?(M5HTo3C)0B|OSsk1*Om*Rll8`>))SxsOdElLSgpb3- z;T@)mGd4SbP6C8zZSjGl8uQU-BOwb`Xn9~w6;f(ICDh3JfNI;f@<0qC4GE1copkdc z9DYf1>&EORLgZv<#NyzbVscA$#EPbw$@VGEQ7et^Jed8j36F>DC~A2;0cgxh#W^T- zy#nM|cXeHCaHdp!3I$al%6s*ajvvOT{z;E8ygX2VQ{<$>cfJiUKjK#?9!<5lRc50P0Z^!S9692=;N%L z*P*OEm~!cK6dQXN)2yX{<)zR>MRx$yZAjge+inpA<+iVK0?ald9weC{^&1xys4|%Q zX;-;oF3n2%1)vNZtg7<2?O2+;yk8!&RGzJ4Nts|wq2(*Sp(kO)R@0?q5}1Bvceyhn zF@HOOlVj_m6}vbBt$_+e3{Vn9g{>F`b~LIox?W$$pbI0e1V7JX z%xMhRFti8jI{JIGr8_Q4cQd71d3gabe5j>b83x}I4YR?$2+pU~TV z_Yr6%))^f?qNWeUJYmcMlp_E z9mQr_qyFXU$exy~X*tT+m6(oqI*?_HTASc-#g0a_;?9G~1x8Cx%{ACA$M$TUOfinm zHGgyigS4RM-Ei=xo!7!Dprl~Afe;feGH617j;*+h!O~Dam;$s_n7YA6E--;y&0_JvRvl1l?MT%>!i>-49J)fiZC^=PTrVTD3!olW=}e$f}O z++L?VuC&18X9UFEPvZd>brDl_vZPj<<6EA=0+;F0)^JW%YvM~1?jPmRZ?Tg%4D_7Y;Eu+Pl&Trb^TkVaUjjq?m`zK`D>`R)rY#eu;~+ z;9|X>rhtv-{jVBqxL3I}IL1O;?!V)-rJbAO6p#X<(a@Hx)o{};LElq0Qx{gLGf`Ds zk)b`93n(i7i^_A>QIUyL#=mOb3qojjLGn+#Ux!P2L{It`C?PjdI7=T6MC>wpPO^}2(PqD3i zXeRsE*0kl*(J)vwvHS5ML-L#rg6H_9yvP(|k-l7NUoMqJX3Zw!7zf=K-)}=-(Wiu+ zXoS^VjV8bVs}$(Xvf&DV?SNN?ASLKfoD}1>!luTIIts3P#ZYd=bY%4w=*OL>%#w3`o)X;Fn z4*6qX+6W1xCOPay1p-=)lG2!48~2k zIOfMUT=A$$!pSoWv$}#tEZ*X?eJ$IEfn~Iz=QsGMJ>4h=>wyoZPPN4(fPFsz-pv)@ zWj{Lu^dGpNh|>7Jg<(ZUOW|PWrzVqiSg-r9NQ+E2e`pG&ESL>EPBtzTvS68wX#Z@^-#k)HZ@h7eex!g%wu?OL`Cg}G%DK- zUwsp4-m$xkHt!g=&9A7wI4n^M`07h(OFW&HCHdI2kRMp3aw|-7fSUQygbSnsr3LJA z?(f<6Vxxx8G_{7Nvej7ZM(!Il0uyi~q4QZKTUZTyhY1I}n)aD5Uy2z}VLVf7M9q*L zBpM?>G4xyHN(LfHj}G>O2NnLKhLhEX6w|KZEuBsA3hZsk*kvUgNQl%MW>u^waIZ=8 z9Q>cv^3Bn*u#K!n25YdSwk-=-f371!pVG9Vo5>Qz~(<{jVenPh#C}5jA5vsV0m3JAkzAWfO?D)n7;@8cc zzhlLuk-hSxJRCE6l6_RlvF2=gha!Wy(l1d*alXO;Rx^Ff)OKQ7ItJ*3;GHsA+ki%|NXn8X;is!8Ap*ypdLa6&RZ= zm}{YVNXS!YebxYqG7EQI9jps)Q?WBKn{ibgzTxDu@+(g+LriRgF{}n{ZveSqQZB5D zzuR>@s4OGpYEnSR_RO?IPIwJ=sfAhTZ*MFTmuC%BQb~mC90?0 z=++Tc&inz}D^)+xJD^q62j0!%aKUniEDpTh!m3)C7Y)(E8X6ca_C{cN%D$Dg89|g| zNf3^VQ2iVWmFNJ!!=>P0D$eA)9XDbZ z-=|+5sLtV8uFB5uTtUL^?*N+tfc1d&fn7ofeW2#ygB#L*^ck&SJx4P*^)Mbdux}uM zI^rWj#hECN7U44k%QZIsx@yC$bpdwQeJXuiFLB62=ZBR+QiRq;+=|~g3`8yB8Sf={ zzRz@{7&Z6~^*0~7kF&hZ3P&794%!sg6by{l2sRCdlR2Jy&iN zpZN`AE4CrjJ_u`_1}(tE8VQCka68~ymKNfV%QdJUMQ|*E4n}$yU{Qc%I4)ozTc@j% zum-4-hWDiu41ZMn(n82ZH2abYxKKJ!T8M1|j3I6o*4i!J*&tC$0W z;iJ*qjTxCi(wGvdgi+*fNDDU`b!`Z@adG>#zJvFq>?pHvzC4`5`QA6T>x+f8axZax zyYL46pu!uG*9d2&uv!J=iYs5l072c+QJ5vQ_*G4c%k|O9b5aKU~yy2z>^Xq{P!H%Rvy)x*|7B(cHU%`sx%5+f8hGo^L6{67&Z; z-YwL1UKDQ~46=%=No-ve66AVMY?%4$yo_}yO%zj+%OrOc3zc#Q%f%iK#l8?nk3WtH zjkrKfv;a#$29Dv|C~7VprEZPfrD)f4lDF6i>?CJQT!{*}ZMiB+JL|}RO zIef#(ApJ7|3 ztcAZUS6Yb1^5#%{X?j!`Suvm8rQWDTtD)j*pUO1N*tqzKHc8ghl{@1G1h2Z{Zf%NZ zN%g&|9G)PkYir6jVneB4{ zUMbZW8PU<9U&eDRjpi;WFM)PVc1?AF4jG1}$sd^SP;m%UYU5)J%+xMd*<@qy+U>?6 zv#d8M%wK4_SR_XSZ}Xxp6tE8JS!@1t9~31{rcVOX1+Tlq?ZiY5>$8NHfuX*0(%7du z14FbS-yOAWfF>t#uZjD8auCk-hKJ|&9AkBbh1fF2^D@MBg6I=Gmw=&(ss5T8{ECC7 zCiqH)YvA5kLq$!LYfPd^5FgEtEoNN3#Wpi`1aoPJ2Rqm>4N-;ADY#frc!KxaLbcT< zRFk^GGe{tdsjt3Pw|6l!>3Rx$K1|N&X&mu)O{i?2YlF6~*rC=ouO!ldXWg3-jIw{l zkGi%Ut*RKIZ6j#2iW$5k7TclNS$4fHUs#_nd?TLCl`nkGi%PH|bTx|&S+--bY4c5X zf;uFznZhvM`-FbAISPHmgs^4XHPKX?#2R6fLfE*&4aJ1)UGWEM%UVnFUFZT6?UUF_ z(RJ$Iyor2#64b`xj&Nk~F(Qu(KIlg}6l1$@q-Ul{HuK}MDXw(e#mI(G15QaOyFGda z^XDPPQv#=W9Aqhs9-P~2Fgdj9f%K~D>(PcCJJz+0#y6OB+)AY4;m0G?=4^i)5%p5_ zibsXqqV}R@Agfr-bJW~=JgJ6(T09Xq@>sXR^>uAy<%FFABL$_j3zIr-1cClKv5)0Y zR1TN`se*n1$>zi*QJSoZEsKiak-)VOzG1U6*2j;P`OWeV<6Eho4nN+^M~cp|H~77)(?ASaZZA9!$pPb#Hy zcuT;1BJ^{1o{iuXs+Q``8${Rx|p>7(GD83r3N(I;_n+?T>+*|KvAmjf$L389Z@uV01oN^bpUQgK~QmkhWcnpuWnS@ zyp>(j0Rirvq>(3W5X@wK2M6UUjYapNwj926tT9N;vuOs;)-O$5>ZbTO3E?pBWA+mp+ZZ}epu+r_3;FbQZTpyQri1UhEzz|x#f0gKqof4%Sm9u_ zwbZp8h=I@%l2Bu)AzF~DbPk!07zdQWolN{34jPCH1zVAG8iL)LZ$*XAN!7q*y*28v zwQR(?w&~D$D0c%M)`EUug^}uNdGqNN1a!s}r?SBD=$eLVVWcpA;Tpt;nShO@4>YZ= zZ6-8FdkVN#$MK5*0Vr zmVkQ#D|8@jI~E{7_?|D1sOcP=33!_wq@OUN@Py&q(JP_qmM1`Wkt7^0Hek602l&>@ zviUs3S8Mk+b@W!T6c_mK+NZ`C+cOwAhk0;@E<^ z(L0jCq~SAvqBp0y@^brwCSok(_67fE`{v7hS`N*93Pxd$qY(2zq8`2{GsFG=`3Qzx zPQiV|hdIVd5xY;T>e}cU=gU~PGj7R^tcmpnyRnbJ@KYBe-*;EQAD=S!F^Cg;K+kd9#QWBo>7!w0}d2 zSAosh>EoidM{CIW4w;+zh~_2pYGgL7*`?q3&gHI6%BAUP*vTB0m8h^fLR93_l^$S!NTChT+M$ZirzROlW?(>r z0~*J&7AGnJI+v|E5wrAuDT|0lr%<)h!(yiD{dN=AuLz2Gnnd(y5VJ!CaC3kN9y=aO zL<&bKnOS@o+~Yi;$TA#ad4pxVdZ|3dtS^`>vr7siraE>fTd9qwWeoN4##)Q(PT@{ z@x8oA?`*L=HduWd;AGdgL1}6oQ4 zDloNWIrT;TT<}mI#*@nm|?!cH;AxE*a}l&?Y*X|%8p5~SB!M4 z5u-Sx0sB`t66;)*#v?pQI2$huqCpTt5sO%i zV{qTMMO7y#61swFVDFq@*k|aqVy_8R_$Vzx;rs~b_53wlMl41$u$KGYQym9m~5qoP6geXu?lvulWhuJ?kQ z*|@-0G^`|ZC%1BOPU5PD`X-dWywnO8zgr9*oM7i2^+XA{OO4TuJF+=!(X+qN%g|Dc zGNi{KLi~^ghsx89RUPv~^FucrPURCI$?iHKS)(6VLO~0w8}LhBwm0>LR|=jSzR|6! znjOO=Quo7-R;97Mg#RPG%b;8hT&7e>{iPP@QW~3nifVaaJDP=G3fYbb zn~|RZRMS+|fhj>fTAyR47-;LvLbW~z3L8_%7&8bklrvvCfu^YRUB0{`Upk3ahNGZ< zE2vxRO8iC?|M+YTG{!6(#xzu!Pg~}X9az;VbZhHNzDs=x?VGkiVI}gVyO258IQeXdy&+e!dhw1J9_^>@1JSb_#2djin6+~s>)1(y<`0i zgTkp!_5r_n#z>_EG}Af~KV}EhpR2Fx0#@@N6pF1=xXfl^DFF8K>hNb~pmiNPuz-#| zAzxUb-s6z0#ZOEjUa2><0Jf#LxF=?re5nb)I)d#+Oo7NeUp$P{GJdc`9m)A0oo|Z} z)HF=+CEOnwt*NDyP%XdXd*QN9vY#upyvt(z(=$dun}gZQx50AQ#6x}J*hKo+!(q%d z63gkmTJN=b@22-&v?Z7op(o?@HzD5!{gAl5w>46**o*Jw1&Y*2U0@7UTA9#h4!vmO?nvGH`$>3-^gO_-f;+tcbl z8w060I|oJP{K^p4ly&K17Rq#+GE9yY>dr6dDix><^AI6`**oyMezARH|n~G%2%frqi(&F;g@;eNuj$YhMnOO`d{;#&d z>i!$G^$aZYRrpyuS9QlE-4X3NWrK+X-OYVGvruib@@=!kXg*U25C&TwKQ$5kb+77# zd3`yY67D0EmUHA_1&gjKEm!Nzr!!Oh3ZcpIReAhkgssR*_v3*VXw0hcH2{6Yd3_&wL5MhbnuHnu!tO>TWsIhQo*%|bmarvVfHB1X)v zSeCXA%<@Qaxm$p~hSMo4xCt`FMkH$ZCgS19F2%%I-5b#^`YNJHM9)ZqBs_ zDvjdPWrv$e<7Pegy0wcF$`CW%JtwZ=x^z@;}OjA(tLS} zU&5AVVX=^J$BM0iD^R@g?r?iIS!8$``leaDq*=UON`vRDI1}QjXO1pRCLH?8tWmwm zCZan+x(m{WktmMfV7tteu5_t{`#~LPcR8=}Q&ZDSFS3dvb-inha_7%lIq zeYnPf>eW698mV%fYv0G=Po7Zw-g!SB&}UMR_Wj@`qyHze)!Qf6U@He@ zz?hYTC(m2X0;Xv`^*~$gTg3c}_NgpP`(dWua5myjD=yY9j?Juyhs6*=^~?KgHvOqh zTys?iOB&O6{75s}nRX8QTGCTQFyq9i{Zz~f@k&|5QsSGV4H?OI8okEwyz{QMM}|E! zR5kuRe|^Q6!>8(A#+nooEQg`!sb)3Wj9yquAU?KLpzttK#p!TEr{k$*wh^9SF4tn5 zF*=VmYN>wBfDu9a(mpF1Vw|1v{3CTb-#!~|WDa|D+U*L{vsxb2AHj*I{Up^g>XG)j z_y+}4s=2ax*zAIr#4R)MP&KRz;dj(0tJ!kc;?mZM1`g(d%~&-1afOXPLr@w1mwvM+ ze0Jn4NBdBGz7`XC=^5-Ltb&Wgb2OHu_&n+Yv(ZnzJdRUw=^2js`K$&4@Ux2tH6nT23jwcxr)9cU1+>% zh2zsS6LS_cO$Z~okJBhUhgHYTR0x}22D~LUcG}NxNTJZ*OMS#Bh(;Z1q;AInCi`J-zBo#4(2rkna9KLhjDH?>(|g=w zp~;dNtKrgsZkf2X+KfDo&o^;3KE_;6ILp4=#B%yujlR!{53M;rQDH zTUqUw>X~)zkD11q;`x6`!f$IhdO4E#H16ebjvW)zEag@LL}Fa-kRP!KMN> z$9C$!ip2J6U#d>0$GkPl-HzIzp^cVfe z)OVD_!a%4Z<`lttM(O0+@9u3CLKCX7F_k(HU?Gj zht%Cmg_qGDl)_`Hu&4RMOLym zN@MV~8+(*0X2r24+=C9Dc|r*Awe#78y8dSgW%UyK!=D}UNR7&1g?K|)TWRedP^tN} z6T6w^oUB=~{bQ&xTpG-vCw52OK_G~?H z`FY;BH2P2_Ws}}#)eNupwPBfxbMV(gljTunchKYhaX;@b=P~qQQwCJwzB^nXcoWiN znN`1RMzHmuB$Kj~C^nWo%3RxQ^SaRyn(1O8y_`Zj77gx1{*m%M?%Ktn(I~vD{{RmrES-F!?D8zCCX{l*gLEp?91xTfAZNVIhd0$U*CNbxs0Wq_&|InWJ*)A**qzky=!MyImr=d-Lm_)Rt%A#xnBLn=g5_lku>aKZi-qb-k6ZV9(eL(Sk-k4_HfNeId=5lZD-r(@@2nvq`EWGg0G5cIC*&9EUOPiEdM z9D4HRkP0)qCub+k3uA2%D+e<<^G?uA-HLm)xJ_cXUj^=8f$dQ!lNnsW53Rslc1G!p zs=#9^@VE-Bf2qyqyLSb@Uj?36fhSkssTKIJ3Ou6%&#J()EAR;w_@oLvw*sGDfeRJ5 zwE~}2fzPSH=U3nb6?jnvzEoI!bh=DE{1OZbIVbsfc*qHUz`Ry;aBO*DE+U&?J$)7i zJr+J3nYkq2a$E%CC=9nAIrMq1!Fv8MhS&`zp24)0x3;%cy24wt2l|2U*N}Fu@ zcD~-RO@sXKW3pCEOfc9J!7uUgMbpcxCoCs!%FtS1KOEnoVN(2(`<(-_o{H? zutcl$@$j|6tHU?^MH4d~B0}zd(#BD}Lm_d$6B{{&Ct&DM0`B75#dG~D6x4JC@Tn?T zk_qYPZZjSu!VPCkXD$Bvvt2`Ba0gjh4G}bpznYyyBD`FWZGJsDgj|}W8eBkbg#g5d zsbnlNynM~i%j{G4+aZB}BGXIY5JD0q-YAD;=?Q((J;GCM`2JNWY8QN4pJ6;c4c0ZC z?3zYWcAHfmJO|W z*Qrw{^&a}h{M;?O9{S6=RUJp>njaiK>E>ZS-qGP-?Y`iXwNLGQ-tKoD^21k`{k8cW zP%eoZk_TOJ=e8ZTz?Xj{c5prL@81B%ow#Koj^{eM(}B*z ztH%8v@Au=?(X9#GJD$tBPl1?njawJE#6eMR9RsQjs5=l#TI2cxZHHIZjl}yNLR0WQ zQ|MH@TbUOCSuL*!+#dqEH=xG?dI`u{Gg1X0GZtWKD39M;<+B~sDMrb zItQ;F?%IIv1X_ky)~&`n>)XS<3&iv=91f0RbPlMuM_JdkDJtm?Jhzz}1~dk*tUDO* zN8&Zlwd37d{30OJoJ)aB50(P4zJ1(nK=4LQ?|D8R^#?U2+LCA4h?8FPyw$RSHE?H76tD5fbImcxKDbN zcgJiKm1QM3E8m)cK7n~K?wy$PsK%`aV!l~dJJm{B<2C~_ZhIh$`{`B@8V}BN_s2k{ zLlXl!6v(uAZa|j<-GW!vJ>yZ{y#_=*&AYWg*1G=$vfMgPgZ|-_b!`{{#tp!ClN%P$ zSRf1iu}66~1;|o9JfIUi%DOIH60U@AS@#>fTj_rb^gD5P;+^T`-Ge~S;FWi8dz5uw z_|UA&{KRx^OSc)&V7#_;)9`+*(8U2Q4d||bo(6gcudK@+8kN2ekkxH4kd3$9L+Jhi zO$C~X*VgWIyq_m@M?jBzlyxrw(Vq5k?-N052e`iit-}jXavm1tTMM)eURgID?^c5S z0-6S7WjPVZZ0E@Vl|35Z&I9@#UIW~H0lnZ+ANLLrO8`3##MT|))&W^rGSjW6^R6e5 zS*~q>EZ-e~7^B9G0kZMCm*=u>e<0emygLfW`g|_XIe6vWjh@T8+kvcC?+x7JfqTJo zdG}^Op9GZnX_RtZKn)&k=bC|b$1Cd&!aMWGy6GNm=Vk%TQRsys^pb$?0;0Xjx+enn zQb211`pTocOC4@jCGY}DGRyE1khT3gK-8fj?r%WM<209>VHS9p>jBgcudEwOgjBNb5FnOd zq?-ve7q5|SK|nVJ^khKq2lS7CI?s&aHU%_1pa}sT?or;I2}HfBaqU26Z7=fZl2kNL z_i@*Ovw7hU9%bD3vV(ACCJ$#G-?qH8<+|fX6-FfabApSSR z%?D!LYTR``6nX_@y0Ofo8uvorJ_+1+f$IfV*Z1~_5wEP<74J5? zOb4<#We$+ZE%d0y-4?jVfaqyu-RnT>@XESgM@J>y0m$O+8@O2k%>!bowscnjaZcIN z{lTNWTLJVsUR%1aJy+wZj)~Ii1;p|Va61xV{BG&?0J2nOc$9Z@fovYUz@w~N3dDS~ z?k*svvWt5Gh;#f%_W@AVY=-v5JLN{Y5kTa&b}e|PHf7!6K6HRP8OZeXT#vHuN+P9v z2atIWPk0V179cCZmjPvtHLj!U1;lklM>p7`9&R@v`l6e;eSzpPZstz^p`olh6r5?( z(Lk2+nE_n@WSVn1kXgMueQ4e-3v$l}Zly=txz#|_q0`)2ApVzi>w&ob80I=2XZoCX zeSl~gM!La3w265)%5z!Q0>ttSaR&pLjhN|C-kt2_ev>{M$nsbW#Cqi24L~*rJP5=# z9qIlI#QqrRKJkdL9@xoZJD1@9iCTAbHId_!eV%z7GRD-n2B2E^7tahrUfZ}OkY4K< z=X#;Ul=&ve^g^vElN)a7IP}9PSA+ALxGc3q#?G8jLwQiDU z`Xlc{B=fTn>j&;|$rMAZo!r@yIX}o8=pGfbBrucRQ(|rj%ry6=nEL{Agj*}-T(l3% z+~|ℜ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 z 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 QyoYM=KXd8-r!V#Y0 Modules + { + get + { + return new [] { + new ModuleRegistration(typeof(IndexModule), typeof(IndexModule).FullName) + }; + } + } + + protected override NancyInternalConfiguration InternalConfiguration + { + get + { + return NancyInternalConfiguration.WithOverrides(x => x.RouteDescriptionProvider = typeof(CustomRouteDescriptionProvider)); + } + } + + protected override IRootPathProvider RootPathProvider + { + get { return new PathProvider(); } + } +} \ No newline at end of file diff --git a/samples/nancy/customroutedescriptionprovider.csx b/samples/nancy/customroutedescriptionprovider.csx new file mode 100644 index 00000000..920ba177 --- /dev/null +++ b/samples/nancy/customroutedescriptionprovider.csx @@ -0,0 +1,7 @@ +public class CustomRouteDescriptionProvider : IRouteDescriptionProvider +{ + public string GetDescription(INancyModule module, string path) + { + return string.Empty; + } +} \ No newline at end of file diff --git a/samples/nancy/module.csx b/samples/nancy/module.csx new file mode 100644 index 00000000..830772db --- /dev/null +++ b/samples/nancy/module.csx @@ -0,0 +1,9 @@ +public class IndexModule : NancyModule +{ + public IndexModule(IRootPathProvider provider) + { + Get["/"] = x => { + return View["index"]; // "Nancy running on ScriptCS!"; + }; + } +} \ No newline at end of file diff --git a/samples/nancy/packages.config b/samples/nancy/packages.config new file mode 100644 index 00000000..fc9895eb --- /dev/null +++ b/samples/nancy/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/nancy/pathprovider.csx b/samples/nancy/pathprovider.csx new file mode 100644 index 00000000..9b11d03d --- /dev/null +++ b/samples/nancy/pathprovider.csx @@ -0,0 +1,7 @@ +public class PathProvider : IRootPathProvider +{ + public string GetRootPath() + { + return Path.Combine("..\\..\\", Environment.CurrentDirectory); + } +} \ No newline at end of file diff --git a/samples/nancy/start.csx b/samples/nancy/start.csx new file mode 100644 index 00000000..7e3ff4a8 --- /dev/null +++ b/samples/nancy/start.csx @@ -0,0 +1,27 @@ +#load "module.csx" +#load "bootstrapper.csx" +#load "pathprovider.csx" +#load "customroutedescriptionprovider.csx" + +using System; +using System.Collections.Generic; +using System.IO; +using Autofac; +using Nancy; +using Nancy.Bootstrapper; +using Nancy.Bootstrappers.Autofac; +using Nancy.Hosting.Self; +using Nancy.Routing; + +NancyBootstrapperLocator.Bootstrapper = new Bootstrapper(); + +var adress = "http://localhost:1234/"; + +var host = new NancyHost(new Uri(adress)); +host.Start(); + +Console.WriteLine("Nancy is running at " + adress); +Console.WriteLine("Press any key to end"); +Console.ReadKey(); + +host.Stop(); \ No newline at end of file diff --git a/samples/nancy/views/index.html b/samples/nancy/views/index.html new file mode 100644 index 00000000..9b3bcd7e --- /dev/null +++ b/samples/nancy/views/index.html @@ -0,0 +1,45 @@ + + + + + Nancy + ScriptCS demo + + + + + + + + + +

+ + + \ No newline at end of file diff --git a/src/Scriptcs.sln b/src/Scriptcs.sln new file mode 100644 index 00000000..5ae72e0d --- /dev/null +++ b/src/Scriptcs.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Contracts", "Scriptcs.Contracts\Scriptcs.Contracts.csproj", "{6049E205-8B5F-4080-B023-70600E51FD64}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs", "Scriptcs\Scriptcs.csproj", "{25080671-1A80-4041-B9C7-260578FF4849}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Tests", "..\test\Scriptcs.Tests\Scriptcs.Tests.csproj", "{4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2A511B15-662D-4F12-B63C-7D62BE01487B}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6049E205-8B5F-4080-B023-70600E51FD64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6049E205-8B5F-4080-B023-70600E51FD64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6049E205-8B5F-4080-B023-70600E51FD64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6049E205-8B5F-4080-B023-70600E51FD64}.Release|Any CPU.Build.0 = Release|Any CPU + {25080671-1A80-4041-B9C7-260578FF4849}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25080671-1A80-4041-B9C7-260578FF4849}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25080671-1A80-4041-B9C7-260578FF4849}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25080671-1A80-4041-B9C7-260578FF4849}.Release|Any CPU.Build.0 = Release|Any CPU + {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal From 914a0050e571ba50f524bebb141c83d5d6a00abc Mon Sep 17 00:00:00 2001 From: Andreas Hakansson Date: Sun, 10 Mar 2013 22:18:18 +0100 Subject: [PATCH 0054/1224] Removed old sln file --- src/Scriptcs.sln | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 src/Scriptcs.sln diff --git a/src/Scriptcs.sln b/src/Scriptcs.sln deleted file mode 100644 index 5ae72e0d..00000000 --- a/src/Scriptcs.sln +++ /dev/null @@ -1,39 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Contracts", "Scriptcs.Contracts\Scriptcs.Contracts.csproj", "{6049E205-8B5F-4080-B023-70600E51FD64}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs", "Scriptcs\Scriptcs.csproj", "{25080671-1A80-4041-B9C7-260578FF4849}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scriptcs.Tests", "..\test\Scriptcs.Tests\Scriptcs.Tests.csproj", "{4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2A511B15-662D-4F12-B63C-7D62BE01487B}" - ProjectSection(SolutionItems) = preProject - .nuget\NuGet.Config = .nuget\NuGet.Config - .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6049E205-8B5F-4080-B023-70600E51FD64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6049E205-8B5F-4080-B023-70600E51FD64}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6049E205-8B5F-4080-B023-70600E51FD64}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6049E205-8B5F-4080-B023-70600E51FD64}.Release|Any CPU.Build.0 = Release|Any CPU - {25080671-1A80-4041-B9C7-260578FF4849}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {25080671-1A80-4041-B9C7-260578FF4849}.Debug|Any CPU.Build.0 = Debug|Any CPU - {25080671-1A80-4041-B9C7-260578FF4849}.Release|Any CPU.ActiveCfg = Release|Any CPU - {25080671-1A80-4041-B9C7-260578FF4849}.Release|Any CPU.Build.0 = Release|Any CPU - {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal From 1f5b48ecccc6ec5814bad07acbf25e746b213b33 Mon Sep 17 00:00:00 2001 From: Andreas Hakansson Date: Sun, 10 Mar 2013 22:42:02 +0100 Subject: [PATCH 0055/1224] Removed Nuget.exe --- samples/nancy/NuGet.exe | Bin 651264 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 samples/nancy/NuGet.exe diff --git a/samples/nancy/NuGet.exe b/samples/nancy/NuGet.exe deleted file mode 100644 index 4645f4b35e8ebd8508fe5691df73ce88a4a8028a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651264 zcmbTf37i~7`TyVBGt)EEyPIUP%TAI7He8|DH4yII4TNw*xKSVhg3ylTo43#{y+Cz5PXcM{+8SC^Z!f{J!|NZS;2?OU)knkT}OUpn-`sbL4D!s zT5?|P%!?PEedZ;XB$q8b>zswPHJ2>B;F5(09rMD47bh<{XXoDDc>9#}u?GjikzKjq zP1pAwm*w`8AnfYyDh0tW%0Uo&=p!M4g@hLhu-u13&o=<$U(etS;(_Zg7c9R%2n+&%vU9GyjQ90Fqm0B^ zSyR3>~Or(zN|8r$TnFopVtFqVWpPRtJCB4DW!pWEK=pVNeLR z|7b2a*;q74%t^9EqeEGYZVt0PuI-Drb3d7rmxk(Fv3XB@{FbjBCF@ssa!zh)< zvw(-eyoXu9!zh@CS-``(GnfTDjB4 zIH8zavIhye^KOJkPibrfgi?*4)q@F@5sy)mL8A}M@dboRHPWV0BcCW$ z6Z%Np+uxTjr%1%dV_Sn%uC68A)mNw#28I^jRVgG;jeBbVSNG+M4H_*!P6>nljnQIg z*6A_vl%N*X*rF|-22A4xwWv~AJ!PaXnj1MJIqoY~iV2k%uP2)>M^nX)wu#3`5mfR! zj8m{+QH?ipABF3{7r!rG@uhU*bgAlExajIDRZ0V;b(K>6EnPu$b*@q@Rq}2pm>B*1 z#^;{PCHoSzmK__*cofw?Jp?3YaUbfw8VQ7xpLAdfW|l)ksfiU}))G zR2>x@_YT0#Qjp7){Jlc&E9BgpMd2awU8o@~R6W%a_eGUxi)CeSsnJT5P!yHAP>HH5 ztr_}CjX&k6)Kf^gP>o(g;8ypqhr`e+Wd2$zsH?ABDGvX6%+GhNcX1t&ll`kaQh#s{%GAEbo@9PN*m7av28IMv&0g&FXkmme)IH~kn zM4y=pup8(#mjted7!wi>{$p) zk#k^`;6?I%VK_z>L6~e0*^FAU124nK{;c5FM1of7kNdmpivahOa+4_QxRjrSPF$Lm zpQQK1VQC}UD~RhO{AhF==`Bn9j-Wmq8fC=Pjk~PLlqnCYrr`N1R~;R9#8AiTWLl2K z=`#UjX(&&YQq#$xxZ!wW7P;M&Rd1`t=|lsi330QIj#Gn^)#YMFg{q0`RDRrD)Mzr| z_VRdcZ$-RW%AkT??Lx5x!KJ}AuL+JvM7#Ey9heSEMnR*1dLJVw8C8L|4ozf+v*!oh zxMG*`vtX(8Q|o=pja>s9yGH4}!N61>)k<=WH%L}~xR1K-CW@M)uIuOYpu~&0$-k*b zOz77Jn=vU>_Yg()!1_MqbG0W?+!&opsyYfRcC_h8Pf26t$T(eVQ)w`YnMjmWKx(yA zb*PLHOEfk`qLOa{2%nb`rU_8LAfs7dEV|YPJ*_s-kl=ZvX?+`%8Yq-zx1(mF`f_-j z64auk%(M0=Y}y_OU*D3s!RN>fajMk!Cuy8Z4&ad-$WQk`&*(ZLi=}(1yRP1HwJ*P( zp5oPFC7&DwQeR=9FB(lilTLlpWs2`BmXm{t8$TRy*;M=ZGJ?KH`?UmBBSxCxA>h|g zEUU{V5AIOj8B09Rhw*ZCRDmoMW2tVb^-AH^3wFD)R9)FqDx%6xz=o0Bc>5(EXb`4* z(64FAD2~QxvcNZJE?EJc6n8~fKZ3VO35z!chJ)QgOOzlsA{nemZ3MFi92Er=`J(;3 z&0zuXfFZpeW&saF1$meSJd7dA!z|!o3p1DnJZzf`W&sb|HiKCJ7=lWd%8y$S!{j&^ zoD{%=Wz%#A^j`Z59n~3)Nt1<+Cd9ZpnqMnx(nW6_4wGX6sNB9TyMxt)Q6iPlNjlbt znGjS>1`u6(&xloUiRK6U5x>^gX)Dg5Z3VElKH{2 zppX-MFDHpZHH^fed!fP@2P0!Q6Yt+uaHi$8ae%T8CMN=WDz$rQpER#% zz%fQdQVO1pg^E%mL~c&2A4xStXockC)_fLE|NOAtOz(z)3odo z)Yuo=%pe}?;+>|0$tahc1Y3)|{7eFm)t`LD^O{z?@4<0YyAe=zElt_gT^v~Nc$xuq zpCH9#CCPhA{caUc6P29l_ukQk5H96XBa)I1xRXIyM*&XZc^N9St2Zn=(l=$2K6@&0 z#(&mlX?I3XUoHzk78q=Jm<53CY-%WZG3k+!qk`>FS%^|4ti2ijEt{}*Pcs<0)5$n= z@RIfsWF%H8qOkT*8=4^?VNn|QmA1G|N${SL7->T@5)5q_i55dXd-`lDA`~WQXE^0g z2$|7NS6-d6l2cIi7dna^C1;R*JbFJZ9VJL%+#S~T%upJCXGk1B4EhU05Nc-=(Z8Mw z@@n6kqV(W)YqwNww~R~P3_T0NQzB**C(h>8LSf?{%3)7(7^tCjR=0>(&CbQBYA08A zFCnQrN92^!l24o~a(XQ$=MhZK=O?UP)hxyTDi4&+^OZu~YFat4jN5aj(@~+ZvyzBl zLqEPG3Wbe-Dwk0!$vrca#4NFC6bo&IQDURu3!~R*g?TtDOyo_-W3kmY&>K+Rk$%0- z2x~vi@KPaQ^iQSa2++dX-O*b#j`lAI%N8HXC%mN;UE#UjD1w3p? z2D5;N?V7`NWFyzw1EZ|{i$NVrl5h05(G>3!Z!(6`L zzMP|?kBa!YN`(ZskNE`BVt=6-3zI7Mv=M7D)$K>Dyw{|sHvxrIwKf5GYwD23S+PbB zW&~m-EKI&Y9HAKV%5$sWH{{r3?Ie`tYh1N;@=07i`CAT@YA>r zq4Pu5*a{(39Wp>0F6Y;$V`QI}ZnOZv(zyf*J;jo{UP+2!DVZQpat(f|ERpb8^@fh_ z8ksYpf3({O3Q!LV8r#Am(|C6+0QHygA&WnNSBGR~&IQdt%1l0zk7!U+xp&JM1NDn& z0IGs|7zn<~6M1C3M`xs+02`13=$*-&>J1BEbu(72<=?%Zfsw00YJ(JDw8j@J9X@eu;&}bM%?{D)w37$0ZI!M#EywHWdB ztoO#JvOI@fjhrc*Z|B(orO+Tw`G{!dg=&r58^}D4lG)S-?M{vCq2CRI__Ii4i16JZ1Swe`9kF0PBz_PuIOG4H73M} zcTjX&$e3D4Ftts#Z8jXr+=OLa*|%I)mY(4ApwEGB{d}fCag>{+it_e|04i4hQKioib zgSl~Fr>2!y&1||YgI$i0ILMbaJGfVf`1qM-$DrUCRycMOU)U={sdNbCwPEFeeGp& zG-5P@Y<}h6mt- zG8`W!2wprcc?pvn2r349yiR01B^euD#<<#Fr<29*X80WbL;KwCU@)4#`sMa=6qq(K zba#Lrx_9ZffAT=l`bapT=eX)A3@4Nzxl#D4LDS)e=doY}I|Nnd$9@Ztu5Sq|kUUWn zm2hHzqWj%V&=_+7JbDS{R1%-i^aFWNwLT9EKn55!?_n13 zu){N$1w3p;2D1RLqr-^qPrWs4I~K& zznO4vSj@Ti5nvf3IRfftUR0O$g5m+?44_uKc(Ukt%ez^J~t$uvpt)amO{|iVhta6_b-7=%>@8%Dg7iJy{7bE8VLo zUFvJr)Y=ft=_X9gvsFc&X@{F>#JpSSJNd`StF0huUA0k@6;oRULvo{vRrymrwPEic z-94xr6zqYG)YXUo;(PE%A42vd{K;!b;DfdEAd*YAq+ycRwxAaqR2t9>aEr<%Tl4Nk zQ~f?AFlnfYO0jmB2}=deC5lS1hG)XM(P$|u#TpV8>UbpU6V_N(2rItF%WRA&*ag0* z$h4ffxk2(e3T2LM-^+3d9UKR<$Q zEWQEMbY<8}{;a0xn&b;B75e#gFqjN`UGYZ3p@WYo1-uEsz*^+BtG|v!WBS(L!UMnP z+U065%_i&gF?^y3P4ZSk72NRoq+RR(8=ArC->+FL60%N5X(5ZPvO4E-Osba zV&U6)+WOoB1ggu?kAY+TA~T5PJ8k3C%=zZxTNqY~j%*`Gmx?x^R;G`^SV^$wW79tV z4stQu+g;qsM2lWNeqAM9<}f)8gM)+b40fsSQvY)UDluS4r~Xx6=1Yr5QKA?m=1WWK z6szWiWMgf~3Mx__l#+KUV;VozrzsAP*;e{NUuUcxp@Dki9@*db3NrbyCv$~Tg{ zpO_dIOA#U{Lsg>mthdj5g3Ae`wJNz>axnU2hjC|kCQ!9cW_;~n*5so0*82c-lS8C} zJgz#jA5_s9;-cF3!LmtIau_Hu;`zwiewZQns9$NebvT*NV_UPY zgNLl(t7HW~s8UiBBaI_aE}4b6-T9lRovo+g!!7g;Jh1S;UI&_h>Ji5J) z78Q(-ul7@M|6#(5O10m$g;{OM;F!Fose33@x%ON$qG+QKV}w(c(3A3&LfO$-B3qtg zt$`jMpfoW*tb4eRD1hNyN`-S>e_tub zn$AiHHjZlJ_7S0e64WU{Ez0D{Q8y!fWt_h##VC1POva-aPC+G3KCQQITBO?#gHP~o z(@{jG+o4UPzMeF$(o=sSjoa4?c5m_`f;>J0K4h#EAMmA!eJSF!6v^2LLGoGfau)2b zl#|c#R)06`o;*p&`aX&w46X_e{gk);!{7y7C%@9SvDO~3#e!|&IA=2x8<*V$umDjF z-yZD180ij+bHn5d(6!~_XtuzoijoRxFOAVh3}Vf2XVUsnvGJEHbDEli5ktLcT>R`hc3-(nrO7*GcNXPjcZ z$oiXUK0k8Rb_d@ZCuXl7lIrLimBB6aL^9}GQV6bv4*6wtLU#+~%*WH+-;>%}dw~14`3Z{Yi|u7Axo?P!#-38W9}|=nGOzOo zDcePW7m26Zi=k_jP$=}mcD_>~ z2sWR*ZxG{)Ht@sVi1M(X$8R0%cC2qJc_B|cD~OJVEy*M%llGrcPw$6=OuwmM?5s!? z++@?-!1sn0Ciitkuj`EEo>J)Urz7^}%E?>QA=mIz_Ok-Yi~mBkWzNO?sMzxpnK?`) zJyvqL60oegY}RrX9N|LLvF7-l#)3&@fb-?1tG& zRC^m$mi$bSrN%)dW@M4@m>Dqsy8x|RF)a|WcdKL_VO;W(P4cd7%AJPzfePN`*u-uW zSq&=1LdAE-$sV#}*xMLguR8d-viOB^Wn0wPDxr2m9&1PAP0v^>ivf2~D~sMruVvBe zvpBNJ$bdVrg{7TMVq}(KwOb*xE3>h1%nF%ZDNcwdZ+^`7=7%4S$G@UAqS<0<`iM+x zWNSAJ^})W>?7#RgO#Ka_)Ar#BS|v)h`f#CMo91 zaocMgjdG4%Ie06gbR#BML9q=j`85P>vtM&Bq4)8ZlHU+B>`l6?|Hk34*0N*)h28+# z7N)h|!z_nk_J-K_@_=zC|Bby5Gfv4AZ7>;5msCW@M6zv}MSDwHlB+zo4f}2TlESQ) zXzE_pR%X#U>Mf2PZV8&v4J^pK zM@d&8PJ+OEzg%@I2)rOr>6W|G zNa^>BnD2x}P2C7(5;VSC;e|HgD#*{sg8w>muoQL+*a zyfoy-RR``Ya zh=J;VC}#cl{3L(i2SXK$n&!U7_>(c44p=jVI(tN{dGTo55V=lG5WDeV$JvrEcBGNSiYrFwWPnT?fhQfVk!AEsH~~C zYJPkTi73XWD3J$yrC_^EQ@oj)q3CTt`1pzVP*246Q@yJL_?q9eR>|fQWMkDTCe)Dd z^cT`rcx~3QUYgaca{|dBN zuyA)&JkvA0swoCGzmtz$dxQ5>+Rc=Z*Ekhury~RkI`X^fJYc|`A;_m0lRO}Kh~Ut| zE$e@yINCpZKZ)_>s!@8`soIwxT38w??;}k)&-N=<4OQ!n2Y^{)&&cWpe%MlZEBRY6 zmb8Xnr~Q3^nbw)X8w+wbUtuh_xXrCHY23ro$T6GyBym#cJ84fsi5E z7TPHJJ526(4E`%`a~sCJjTGERZEDh2vg2^$&d2OcA)+ewK_ZPL^PuKg(*83TH zKezc_8=~m$-^!~vx9I*u!1|TjNGLh0iPtz&>CWK2WM;f}WiY!;XOCmjGNJo9MIA>v zGNo`KZJv$;S}v(@1S%a#>(41Ut4vH4V_cEz5K?BE7Y-yr7sGNTc1xMJFl#JTdfcxh zwq3wyaz*;C>@H|!W%Eh0>a`xcLDIDdKH0JvZ(NYh!|n?A_jo~E>`Fag|1OZ zHCKB^AxTMnKkASj!ShRq+&-#bTdPQxDLAFJ_Bw`seXd?KKd}IL13NE+S-`{2&tMkt zunRJn1w4!<^YknL>_lHSw$d?>YnFmC_I|vD!Es$dFlyt*?*OKI;-!e)b?Vw|ag5j! zca+k(<@}~I8UIpEE~b5%)cn!n86YF4c}vz^9)^>iQsXfm_3aqadc%@qT+lWjn}29= z!*`#Bu$eaT(pD4O03fYz+qy${Bx%RTTBsOjv0DIsI?s`INBI}4Qt|UNUKH*4MDhuW zVV;UKk1bniw2DZYlG2ncP00j`eMl^D@7NlM2T7BTB9d~_l$9ox^px;?kkVb}e*UTT zw&UO!uFd}Wz3M20Z@&w~>3!JOrfmn9XWIchV4hWP<}>WIaz6up&fQCSwECOnQ8vE< zuc=zKjRS2|2imCm7L?;OozEqiyjTDl$lvM=W&vRGj;U+5T&)0(o9rvUVW>Wi`1 z?}!K;3e+z&ak{lF(ogu%20};6rMwI-SsbuYFc>$Pm!Q{{(nWp4YB_vDT&;_$)}V26 zH%;XWTB4vVlWV^08@u*m5_-Ld-!`03sqovjA-ubZpjnzn@Y3Zen6Z=+8!DqHbY7u7 zYC;v3Am&knp}XmAr1sNuPJ&vLTY_2IsI?){I#E4_=_x@i%IykLZ@E!#L!tdo_KUch)E`)CnHqgi^3LKc_sGr$rcn@#>=CU;vnp;jH+g{18T@;2U~lr8{Rxc+A!}JU9_d)gFJEz zR-&NP(8aut&U$0jY+u$%kOX{O$V#MfAhO|(y=4akoW_+u5Sv&{kh9Z|jKzTDOE$TA z8yS1W)7HAxqS0Jenpf1x9%kij0%7f4^w~i_w*9Fowa+%|ggK4JNq3BHR)0lbj!lH6 zm{iGcY^!FC4|>R^#Vwt~008%O8KKTgs2ZOW}z9hbMY1_~in9fCIW<5kBMZAhqtRCNg2(2uE(xOH%dbx>)C z9$P-gEl-#Y4Qe=6L)EJitfjbC%&OkYlaG>-$CS{N$7eQQlS<2VesIY9ydP7C0SzXdM{o>bdzFuJCwduCe;EMNWKC*&*+`)b- zo417`UQK$3t-5RTsl%pj3)e+v(ip8g{;5sQY2u5Qj>3+Owa3T)yqdE$fHqxc?<+Gp zE85Q@ThwrHb^Ceb%%+pkoW^&`dsDc0**fK=J)4ZYx=plN z-5v5EePFq@=^zofVtAQ;{zCxsW#gL(9jY&KQ>=V2e@CxI=HD-^r|bDGbG04SlgNbm z`}!@JM7a5cFWZS4a|;Mn*CNM$2VVI;1+lF6L{4=SeFO_g^v8fBq>pf#VC*=8Gm_V& zbp4q+bueQF-X!-qm?VxkrVk@Mqepfm$PmB&td0a_e^-j0pdEHj3C_$MmiP0N-mhYM zT5+rR(%~blX0M=nZIRZNW^wDWOR^2%PSL^>#qfU1ZtW!q_O~`fZ7^scqWq%jva=?> z^QWgpe7eCUF9>Kq$rSw=vt-(wYMG`7Hm92Bj-V|_nwT_EcdB~dx#0xSZr^*7 z?l8)as=K1plx^mj8>kfA$<&bLQ0*qx6!`bO^*8-QK+$&A`|5FfPn#2MDckO#;LQ8I z{tJUgf?a>-mtl|hVrny^oI6~t!ATG6^EYJu)&d^(stjfU54$mgS-`_?%3v1ouvZ9% zF1b02vw)AgC4*VO!`5an3wYSA8O#D6c3TFsfQQ|l!7Sim*9%7eug>BuKwRIFErK`j zJkaE4+y5#*2TOj^ir$}!Zq7%V`$%j)61s&T`iW;ZYUa5k zo7IAyo=*+(eEne#p->i+$D@LtRbCzgPJ8X}(qI9V#QvRwf|rE>JAKuc>CusOpqwR5 zE4?<-9G$g!C%F(sH+>Sgw246W?D-c$`=p?DLK6YYzs8|E_Ft`*zC?A$)8+uRHBD68 zYaJyGQKKuWk)z~t-ul(j@fdwGGw0vXN~C2PkCv_KM#+^kCVIG)NGji>Wq$Q2d8PQH zYU1&oS{ePYmBu_VhLs>w7~Xzf93{6YA(QWsF-Gc)!#}nXYB)&iK&Xw^&_S||xrb56 zI$a{364as`bHb6vYuk_x7t$x;Y)Vjza{GXk-pS%?-WErFlh*pU++ow%PL#YsnZK@$ z?h4WUqUZ{0QEp%8CfmUf+iQ2GI7}}Pd>o!>hg{y2JZ+U3VD6xO6YFqFs>kEK=QvNG>O&%Br?0pQ&$+MV{3y&+UD^h_T;L#jJHP znVR3b*tmv7w$G|N$2d5im5r?~6iGVQkAbu8EZ?EzlUqY>oOANZ+3)vY3P5pmMn=lT z-!{b>-BO7}k!hTu-pXv-dV-AmttVyMdeW`4V|nSl?f_#)^L+YROP_dUrFT2Ai$AV zcl+_41*vH3JZ9v(!w?nkghGwv))lLbPf&<;-hY{{CDXU}h5#0#(KSt%bISm+@5t&f z4$dUABieXKb6egq)Y^;Y~l-QQH|@`@wNYhhSPrjX>u_DEOfh*ymlZW??onAMDO#^`YYM0Mp!av zipoSI$C$7y5RS0d_d|Gw8LEWQ23{_(mw(xE*nGiJl7*D)O|+$s3GYOzgn?Q~ZDe?( z5040r=85Dc5_@(Oq-PY{EZ`Ot%x?Az>ugWNS<)Bs#^ZP%c5Da)`gOecJN}eM*nY|* z?PbZENXoRc!Z|!Ogsd}3gFjGR7;YPp$GpW&*%gbi%0&*g004&+ZrOQ4eNOMAjtd+uaC9TYK#RXY^CEPP=iX z`ypcxJPegRXhDR%{um72rGb(j#sxoDbxU* zVNQkt3@lp%_04NxMN`aCKpxc`OY6#2zYCp#R(Hpg5?YY$1EVrzsD>Bltq@}S9z<+r z^!{olqc_#l9}l+wNp=Rd8oV7cnDFiPgJ*6ac89`Kw>Q`@4RXo1d0$uRl?UZ9GE4FL z^6p?F`U)OXYlYx`SGW~z2jzGOqpK3+lJ5icb-Zh{76$rC?hp~+l$NX-+w193@n$hF zmFxt82&8ha@ntdTk2SuR(^!51cQ!CvP1Z;f+fHLYuVsni5T88N8c9b@T1+1`<;iy4BYf8m2BDaJz zQ-WGlLidhY*A=Dea;eBPr8|N;@QPHr@~!E)+7Hp+CSO77_H(wf&eQck{3-8cki%BD zK}S!G;WItee8Yz{UTKLna@amx>U6~n`yw^o{TlA*`;{6;Ggi08sHrI^%%47@HwQ33 zqE~C@ki>`Q)z&n_Q`eAmo+YJc)h4ruVzqW#Gdv}Q?2!<=+C5oBsakuq8J;pNjOL5$ zsv;H*Gzj|5mgU;_!OOx=w}t=N7B2TRai&x!ew=5{gOc$+9Scwgz}}p}EZ|{p$zT@n zu)8vt1w8Dn8O#E}TI-!F5fFScCwt-SV?X}eh)3axtxiDJ9&;zh>qalo^+z_~(ptANz1RI|S$D~(Jq{XL0DzZx6c z;FD`iQBQ*j`NXzo#xgetxorq#IWe;#PKP?<5cUsO0w~XSkY-E{9>d(Unq=;!)pP@0 zz*{j?Q#u3X_QiRCQ~j#q`_gA+41GEV4$UF*ZE8Jl8=#MxR}sFY?s^uqBu+lGrDrm zMz-Qfv0ax$xGJWem#7Zwf75Q*^gId%sRafYn$M5I%nJQcn|Q~ z4YEGas|>9VY`PwPGzVX7obnePoGYSVOr5**|9l#}TS43Pfx&)0NN9=+^(ai)O*memsC|i=64atJ7aY+Q zk8F=km>tE2o2r9-vP|gsimNVPqH=$b`$I3$vrm`5asvr8%Mprc4`hQAQ} zrn>X=GNaOb7{$iB+E~3_tTF?Prv$Yq`Fm5(gx^PkB)%Lptt+V^LwAAwzLa0P->9!p zOqN4}Q^08GfJ>~IX|jTfRi3;GPI-u78HLttp{tYBx22bchj`yGpS0ORD~D>B#m45A z-T+)g@$IVou3I%CAQb) z8nTMp&db$rfi>I($&EaVQF5~$B=Gk>gh9`&AljPB)p`-*LGWUejpZ`oq}6RAJ#F0f zM;y6X^I+3MjFbLsVB}s#*2Bfx37f(bP?~23FAUq|-D{u>p^vpx`fhLjAJU|zA!x2(+9rAY_8T$FU-zQcp5rGh+!9;4UPI*1T~IkhVFYgq6{)#9Mz~TxC9}{g^2Rdp5bFd=(g8Wu!|` z?75t-GSYeR_~Fg{4%63zI@nH*T!YsHSCqTv;}bxa)Pl!%_j`UqEZ?6W>hIUkzA(lh z*}|NgIFg=~VZwsb9rOr!+8o6w}uz-o`W2+GiLBi6o+~WLz$Hxy)3T~}Y=f{D=s4j0iG>+? z?&H)U<%-uUFNfnhb~v`<^&chW`VrKzTfwU>|5n$cC%beml-vDhD(QWSXD8$lq)3;E zZP7K_Y|%CD*S?ziohUVV38MP#@SnU*Iu7f<=@;HBv_YnMXpi;&<|rxs|8{>zReDWs z`??|=WKUB`xuILUkNsKrT%K`hv8%&mBL*f{d!E; z%Y?$#Ng^LKvA+cwK`1sxuTdi%O$Kf)Ao1w+S%O^V_^2x^t z#||e0o{3}m?XI1TOx1U#GvPE&xT7d?%*x{Acz!gFZfen)k(pAzyoq4TVSEw6uY_TyTKn4-coo%>=jIBD^M}Q53YcgS zQ2+GFvZb+7a;_GEn3FcG&DWFG?pl}<)S{#<_?$>3J;Zet6#ZC~t39j&T}T~apYbt} zA5trRQ(6XI4OEZr;gv21e zyK!({O8R_uj(LdmNMeG+z+aL#?K(mevuVeeCCgiS+3H!4tI5nX$NN^0Iuk!J)5bdQ71?Z4JkdTx??YV!Fp zjBzqEJ8+qT&2#y$Q{O&?e2`bfeI#W5EQzY03d|h~L|%9N!~U*MJ88>3{>2H=#gFbT zLYjNaY5(oRod~-9)xHaFQxe)*cQ2ujD0G2BsNsC=NrgV9(9&6i9#-f)g&tAp356b2 z==%zNoDf-Pwr_7HV!F|~&Y$z>Gd1yOsYUN}RY*F?3JY@ya3BUNa>w%|zpdYwNj_zZbmD!%;% z#*c%TD&Kr^DV3o`9(84$G^|Qq1vVBb&PJ9W6CJcS)@=&!*8{g{mKoibTgQqEMXR4f zf~)gm<0LQH$^3q|1=2gVlS*iwuI-!YOeK2a=*715WQF8u9W`x3>OdO~eDNdJ(ljDA|t6g7^$N*aha2-V98>Gjv$9h4|(*Vg7< z(OvUhx>GZ#D=iaS(w2E$G_+4Ev7ZZC+H#r}pG>T=iz@bGmjy@&?6Von0>HStLPte80rMe=u)Dbl$$@U{ky-fgz+X`2_RY=dQc%dP zs;-)ov)yyl1!C4^+YRQB*{>;8!R||rxfa2He-g#t*tfI5NNJ?g@T$eh$Ra)qwSyl>Pm$^C9>e4Uudo9l7JeI=@ zg;3iiL-W^p^tRUq1C{Tevx8$!^YxMG)vJw%pTk3yu@I*jGN$%GP6agTh#59&Z09K^ zn)o^QGY~c`A#zdZenOZ%iFWP-s{w~$+>upXaFn3`o{d=zw7 zf+ZMl+}+t7+yuFok;mu-1h~NvKS{jxavXEqev6kYuI_g%VbdbjRq{8)auqADXu%}B=i=z#9AV5_efvXqGIKK>mqdS)O0vNBEnq^k6>#gRJ|D(Pa*KzX z-`8`$5w7&s=Q6!z0cZ{`nHQ|**-)PS?v-$B%BXf1{P~fjFs8w?c7Mk3sQ9V z^JG>(7NDGpv+oiTe!0o*w@B>oy`kj4Cw1~hlC#-K9;3*g8}<>kODR;Tx)zgmkkRxu zJ!{tkE7os;_iOZCPM8_;p%=*qI<0?gF|7+&VKKjG+AFfGpB9?;ofz8>83Dx@9UAYqJP5aPcR7zCTp2 zRoXXL+T3K7v{5vnhw*2C(2AZy{|>8Ayt7FWe`#}0FW%3B=5^3)%!A1I_Ph<~&Q|{o zoAo#}{N&KxE_PT=h^K^T*b__wV+)0L9khE!4Z`$MR=KP)(~AAW{!(b_PUVPmx(mp+ z9aAE8&){muEQwqBm}$lC1Q^V28m+&5o%%hg>?|ak>RK#J+mC}EF1k-I#UA$*;gVZU0g#+^lAO1}yjuxiI^6}0FR04s zyI$utYTs7fQpz@ug0EXcl-~h6CU_Nmm=~b_MOG|h3%Y&9yDlc_ZhRD~t@obBN2a~^ zhSjw{CJVE5qx%%BpKBZI}EogiRi0WX<0w=mM1*tttMOaL7FI2%z;akm}8NP1^ zxD2tG=v>nQU&h8v__8i$f=l(!1lI^N6I=t)OmK}cGr=F~z~`?!z-RZ(OlN5a_&FWm zcXfbkiN>Yo{ZumgPW4)E(bz#s1bFK#h&zHjE*{h9bbvjhI)9pKvx%uMH+ z4)C9LfbU4bb!CR1N_Mj z@V|6`7Y1kMXWtI+i#xz?>;Qjf2l$2#@Y!3=%+J9c;A=X-pXdM|+G=L{^$zf_bbxnn zJu{sHJHXd;fIr#+ULKm6{!ty^cXWV1-U0q}2l#diXU_M84)7Z~z#r`Zf4T#Fhizug z_nZ#!wH@G}?EvrHc4qoVb%4LR1N@U6;J@nt-)_5^^Ig>ees2f(H#@-lwx5~)=^fw? zc7S*7Ff*OwI>2x40Dr6l{4X8gyDpkJ-?KZwZ|eYmyaT*z$C>Hx+5!H;4sbphJ>xj| zKnM6wJHWSaGt*hx0e)r&_&puqzwZFwZl{^^J*NZwy&d3BcYqHK&rE;64)BXRz#r-W z|78dGjw3VYdv*u-9Ub6b>HvSX1AOTVX3lp_2l&IA!mm!h1IxTsw{&x2f?0$1sN5&7 z0CU##N;PdL!JKD4p3{C*`MdDl9A^iunD;im!fYVhr*^BRG)!9KDM2l&wey{QYCAJE z=qXh>eZm@X(Kfpumpj&`&i1`UKL^xTY=hut@(Fcl*sX=C&8)fA)LbgwK{v>SQ@BhP z|Hywo_>i#nJIW~bxh~13ZowgqFT;o5n4axZmrp|Tpj)8de&=r6cJHXx+U_0I{@I;v z@s6fME}aMA@A?`mr>ru6)qrvTu=!Bf11NyLuW5b9tul)m# z(@&81>m%N&JFIVU<_>Fo4O+I7x&C$vHlek${hIEoRsEyKL9 zNy4V4IaXkpnrF)}o&?{9W1o$2(8q@%ihR$z=s)-?vax;Nm(NA`8=LLIlcA+|v0>-k z@Z1-3rP}CfSk}F2_sUDt*AuZyoO?qi#MalW1>O&-;hejJm^ocxasV0Syb!2QhD3b;40gC$lzf@7 zoy-I9K_&HYL*h&KI<*^*l}X7ueDWb7_)2+cvz6FT=F_khJD2Vc_YUE-e3$$3^;<)m z)P>qf5UX?QkoqCv`fZ!S@FwVb7&YnLXD)@Qj~xZg+o+fNy{Z3Y8~iV!&VO!r1u@XQW#$Fhgr*@XG?+>RNf zj@Yw*M`@Brp{Vx6|N0GeTM+_$ob|)e|DCMuF;99su&VHYm zF51P5tv*19FEQZYdXE^3680rT8}5LnI;*>bRbBgZPIQUip~>e}*L!h?MGly(kY4Y0cQRY0`% zt}VoIayLKqPr}`Of=6}M4`RMIqZ(B;voZBugo^`f8K}DItQxR_P6X1-2K^Xe@jVs4Y4zkJyGbRHV2@ zyMb;DrEB!TNa@=__C&4+?RC~Z(*N3E^>rl3p9<@)orI#*k|t(_4Fd{<+u8Cl!MgS`Q%U6V*lrMWEGF@&%6HwR(F^@ z34vn$^ZX`X;AaEe1Z=!++oU=dNH1$u2MFg8#LCt#{THhie{_Z&Q0gc2r+}}{&Seav zZxCJ@%tdeGA7_u>$zE2pSDii@ydK_a@6W0{u6;KPvQN&B#S9NYddIBVH@qX`<2t~v?*RYOrtrPOT4hOgPKrv-)^P5mj#ZG@r?x$ zk1-7k+>Tv0YRKM(j_$j(-_#EBZK{}Kjli8HF!pKgZd z)qmd%&#(Wf8D3ETb2B_x|4B2t z-;GCWKHnWp2yUC3?edzQ(NjstrC^kxw`|ATHEB)fo!DmSg)K~0ZR&}&b?XK5_uG*~ z*j+aFY~0-Z2!BXCy>RR;o113Zoc~eHW?q4OnL~u@XnsMh*1rcg?i_|4 z`X9m-QcIV-HM7tB{^NUKAav)l-y`1812>BrZ-$L@FQJ9)+qcdA$2~nk&q7qnwPE6P zD#m1*A57z%2c;X40ck(P2+wtDmp?Y!<@fFF!g{;kyY+`=lbF8B+9Vqn?u7<2@X1sL z_ED?kCP(#XuI($Y`;^!JH1qmxdtS|T{ohT`E93KirG2`Y_SZ9}{mt~WoAUW~&*$e; zJ`eGH9=jW>TyR4QBnNSpU}`5aF~X5I&#Et_{m+>h?{_J6hZWHUUk_S0r~e(kwtctLHe zT{HZ_+V0Kp)bC7nrm{ToKbelT0C}RHf1klD;9-BrU>5MOKV~osc-WsZm<2rSnG9wD zgZX_V+N*dJ@9(Fab++1RKhY0(BtO*8Q~X5TwWDC&L)j0?iIgAl%dCfaEVo^U$uDUP zK7J@8yQIyH@l*EM!&I;A9Bgr5wvTeqzF+(S^2*sqGBm&Y2inMgm^e!Qsj$8@4E$Mz zSNO1f2E)Fejw1oplAI;DedOI7uH)O1H=j8tiJyyUKH}p&RJZUn_XK4!)!a8Y`Day+ z>iut7Jy`%E!2Tkb_OR^1`-AZALAgQqQ_4DqrN@o!lfnvp44Wnsl;-4L1>z1;7|!g| z*$PAR?^!+;@c9UxeEjzxKS)04w7;fu&b4=~??2uePKaT}H|)X5&)|wY zoaNPrpJ5F852?=6JI2OjnEHhNiZQ>_YOK$|N){#hO+TxmDRF8icI%s@!H1w#zm*eQ zIs&ik6Xv|Ss7Z-@IJp@}D_z0Pn30q_3;rS2D+D=sK1c$)hha)ki*h}{vZHOtU3SE( zwpK!TsfMvRU}UthLsVR~)BmdeZ+7CuV(~`7BQhcvvBWS-``h3}yijD`qeY06RXM z$N|fC61rp3_EB3XBF(durL%yiRnA}*@US?8S-``(GnfTDtS5t6z{7eom<2p+RtB?x zht1Al7Vxk+8O#D6R>@!%0H*zsuj8pdZV#ZOX0`iZ@*ApoTo#W$KC8$EzSX9*PXMSt zt(FkfqU5#o-+=e{*iE$Ch5Td$2HFU`Oay)_0)jU5<6f!+tyHpE7wG&oXFZYexu95| zumFq!>&svk@UZ?2W&vR5hVBS*YZgW?c0`WGB<`g4IK9;Whb(>E3)|!L(iV3@dz@af zxNO}12r|znDv9ytV+1emB3~bZdaIc^#?TAyioAO*weh^2|4~bS+>Gf3?VP?l_$+yS z%+jmr{9e+FTTOw!x(ayx50q4A>u}gKs?=Mi%qA82N41Wi7Nx6Sxh119uMMpsv}c4S zs71Neph>rJimoxg4fo~3{j+cdwW#DTy!Mv2ST-MSOXcLRyyCnsCx0WrRnPh4?+U2T zNf!Pdx|c%47p6uI$dv$%!M1F!Q8xb|*_5Cb7s|dF3R_s)}O4k>mvC#_9nka ztnLv1*lvz>msxf*)HpS%Sw;PS$x;VJGzWoKt=$|4okv9{*%hXI-?E_1Lq@xZ=Kh*w zcNJmFwjx}sBK%WD5Y(dFiO2WLwMW7eUrWwNa@5!9mWg48qzXew>LyNN0wLulFEW~YV8Uckd-lwWtHh+K}*X?}pk6i9zz zveZ!a6^g3R-|(E+`vp{%FS>nYJ}Zm-2#1mOWy8|C8r!NQUB~D*nte5WeM)r%!$TOmKY_P0yA7 z=|WgaPELWRrq9#Tr#@{ayM#^jvE2#dI_7{*)y=UsOhVAIv=L**A;t=xW2Q2u^N}jrAbi!rN&TO3D&9vu}UDQ zMLFbQ#J$`~;Kzy|wDH+k*p~WMrS4X0K`qKnDfKm$TE4N*!QQ7-_S9mi_kfO~R{JEq z{B)1L3KaHr5bmiL7)Ri|R@^;U-S2LZrji<%tTV0v-eME*Wg2cuH3sk$J9VB>Os%sq z=*@;~3Y14pK<`c~Z;T=`tIq+!T?@ZSg;4tan2U8pw^w}Gh?Ral#(bx9XrW+1aMwq( zb*Mrx1mfeAvHm*hgSk&lr;yvYPi_ZJ;%qG23;a(DpUYzne~0PCO7<3hSle$C@R%o) z((!(>CqzfhuY5O6u$$2_c`?!0gon>4t^ZzLXd1MgXSOnl2PxBb@Uk`@uo)Tjyd7x) z%9YJgu$eSZot4@JSGL;)m*mnZr?(ayntUUfM;E$!8mwy_huL=y@|FT09gT|OL-xAOWuJ=*8R znL&@3T|2!6ykFfIZV}iR&5^90qM>krNG?^Vs#bj2cC);~g!A(P*<9ouJih=>3z|Nv z(~+jkNA=BScwX($Ju>+G+M~_zl&aD@uNgNOw`)pY+htFd!CniXSQCx*chPBo7p=DU zDb>ed)ZUkRc+a@;mTEeRjHkLplGsW*Gk)LS^YEd@RG9zk$)i>;mU;)F2rZt?`pM^PQ zpJON{t!tEpGhdsJvi^K9fG?^2D{1>rsL?0%Yg(^5>|bot)KGu2fKuD_ICIsggS@#{ zNMyH6+b@$>tpDK4&}9Q8?4+b}n7L8Hm=B2zA$U|>=OePqgCV`q4boOw1ShPzZJlf6o-LIPF0+IfdDS>KeY#~@`YB0R#s}wN`Sc!Ux_i(n z?O*BQq0jdmx~$JPWh7U~0Q9RpjFHJb^(aj4Wn9RYq50M~$a7YHT=rw3x_mbtVGbYW zLu4|h_6R40Kj89Bttm~GY(sfC{rsFRB*FKn99ZL=l~3O9n>6h=CEeMty-t<-R#vLq zDskS5=M+`urG1ALAm7n9HPTi=#EkJElY^_>Nc zy{#Mz{MWpA$J>Nv+_}CTXl{FchTFrMr|tmVZ^4Tn2fo|X%}7b@W@<29a+5%Th|B~*z9nyXMzoh$KhjdSONSDd?&h;lH(^je6ozcMT%eyc7##9}g zMcwIdn%EWg%A{CdN@M>~Jvnguw0~S%9c$bv(82 zS3?iqfrcF4QW+bzT?&~-T`G}D_(1?g13RHRV6GZ`pE}@jkT;EHt?k26$Vk-Ik?fF_F7{zvONqeQK{1>~i-XP!HiioXbblS)mot@ zg+C;2vz-TrHydrU_FUDB>gP-7Vb7>jB|Hnw$pF-UK%wp-+~G1}j6 zv_WN_kRX{iB%GmYnx-D~r+=jVA^Q~a3p7&f%Q_XvgVsWy6pe2avU zGWhxP(@Tf9GbN35W3)?qTU!SCWEa|_dsIrJn6RW4_k=%l56aU&8D22u{kY`k$}Q92>yYL$H(QQPjw~rm5>fvMY6&=9jA_ znHu+}Ij{<9(h-K5ukQvbAKGb4or3D@0gn@|#iqw(`Y0izUp;@FK2H&*NkCg~AE3AU zvZO}z0M}CQ*(^fSw)g&^Uq65T&y&gKH1+*9TtvZdMAN(=cyhcS{^FWNwNSe|~dmkHL6 zTO+P7(Z*;LB6a3Ov3rldd#=YEhS+13T&qPBRCOGCMQu%N06wj#d3ls9ReBrw#96Uz z23%>{jXDNmiaa|4at;H=)jn;}DAG*$Q&T*YMw-;-p8(lWRAd-^RTKp37_^q|q z<|wH8KB9f1I+tDGh{9*a(~p1BGt5GQ-;q8)-A8qzSoc1v>21?i@kMa@2<#{^eQU_4@$+2OgOZIJ2C?$s5||1KFJ6_a0~0 z6o>D+wdM@EOH!iq2XMk%UDjNBqg;RUQaH(o{(5_Z(gO@f+lI|$5%$6RJLUdJ`kZZd z-z>Swn9{TVtAszIE3+rHKCy)&_+zj2G8!P4?8h&ckWHT>6oNCs`IC4|?E&r~2XSe) zlDho~@=9Tc{S3uBz;eXe^_knce#r#HM~EOiT%CQ8L9w8vC^&{Z&Xu3rSFma<>X;c^lH-gmkQs1huHf z{%!GpSNw5`7u2F0DN1h2# z`>!UhpcdtE&k}CqkT%q3g?hHg3TjdAb*h{@_(|s)y}`CHq`xq^pYnuOD!WTM4Q>S$ z_j;ws`eskCvrm$yu_;k{faAZX-!>Q4mr{M|>zut)O}b~uL+`A~o&&$yAEj0t-jpr7rUcY^?y@g%m{jL z-aXfbluxO#uU=KkHT8=0b6J(`pOlUH{`oWmCsHRb;8_fByN)o!Q;!t36V%v>*rE_#Iwrwv-DEhM`0|T zku(l#>m?;^fvu5XN>Gc^#%YN=woGXIFaHJq^~=D~2(pGJBgo}?Oz6eWCR+5P3B`Hn zH=DWQN4o-W{Yri^-oE1p)ar29IJ}LevRJwbyeUB~%H0V|x#Vh}xQ|;V8R`O-7V)*0 z=>cfqmTz3cdW~Ufbqc(Y5yXG%Du+eaJ-M)AQj80~n^XqQ>6}7ik{7d$Z8*zrUwN!S-C(YTuqsB|j~n zN`8JZJ2;-w78BzKv}lh&d%mZwwZ&<)3)5*A=0S{aO2MNMYwp8AS4hnb$Kf!3$|Iv@?J zwbUKXoOljdOj%(LY5TsPn-3TPWQ~vBfi9RlPO0jz6oKQd=;+!B0nuX&LrAOEcH~al zD0!O@QvFCP4PT_?$!A!O(4&wXu19hMq)e9%E*U|`2f=fstL;xiIchVGabLd*l{a!`?vu|nvbPZ^sy4g{w&PU-LQ8I@%Qfo=T4x>#1^fc?Fe4a9%4opWtC0 z>Ur$-JofsWW|b?m1}d{s9>F~XT-#CHH@h;s>~FZAP5zbHW;<49`|lQUAbX%v&WaYh zTj6bdW%B~;c;mqT$J(2~$yHQ+|2MaLx@UT3l1yeYlLbgvG88i;Ae)(C3yXkZ6%ZjH z0YpB(>IQs<7eSGJzhM$Z@M_1?hN%gLw(NBjIO>JgMBkn%3a9^ zmFa$y+$L>275e%wJn^LDB7zIa#X=hB8|dpF6xhn!&(01w*8}NmOHs7T+4L~-vmgJb z@c$tHnuPQx_?s95d-=YVukx)w!Jp^D78O zW*T{%qO|H_s`_VYbn;7yG;oHNOG%D#$Z#rS8BWg--OXTNor;+i3A0;la)n)7k?mKi zboHd8?foPlg;*J7zw&P>Cck7@MORO`R>t3<1l1!iQx+u`^mWYJF&)Rm2io$EmzKx#aqXI|!wUqPR}#rmxJ>(EY{2(Lu<^`#{p*^ggw|3Ft?rOg=^U$Qsow=?SiXCeqY;afPZ5CCp4ue}F{7?`;HF5ZO?ml2xDuoZ zanU@2pKK+#8P!y~N6Bf>Aw=P05KP z`@3dzc@h`5lIY4Ou?%9f@|K=2c8Tg^%_4|0kYot^yn}ndq+dXeD2j`Mv5W==DrtLZ6CP zoCpEh{UAv3iq8_9s>=r$9ri^67*RL2agDQ`R(O_Y4b7=v&7RRiTl35fon}*llWQ0@ z*Kfl6QKhO>YU!=cDy|fIK3zS9sy5=mHH7@Rv{O=693TgXf1uq=da zh~BtWI@LllQ@Qv8RFls_uW_58b%ptKB0XxUE~xp_0k%{Z?I2dWjn$zZ9m_qKglqRh zMs1S6o&1@qPQ5@sI-J=!^lv#7jWXYM!E4wN5>(TMV7vW7rKMSC?Qg&q-cwpL zWzEBrQZ7$Ux$G%_5o!~nWd!Sw;WZaSSu##?)mab^NYbOpm&HW$)9rLOSzEfglW0=9 zos-k;%%v+@M$prhSLtrAbhnwDZYdc9n##KpmU&Ant%XYSF7b3SwJ<-T7gcv9>Oi|H z=6F?bG1%a|4fBQHJv52Y?pd=Zh0dN-Q{7>RO4Q{7l?kP1iPpcW@{+fmTwkfW3P3Nfi#H8+gVnc9=4;6L(sE-GA3dJZaU?gP*hZp$JYI8Qt9t_O{@&(2B28O`v}!4r z<+SzbBDG1Rr%ulCR8Q$~z~&AjM9=6m%nkp)!K76?hDbd z{lllmXW@GZQ*ayYi$%hS!X2(4e9a#M#kd_j`R@#cQ zhpp~nTin^>egLHhk?_JfzP{QqHXhrk<@c-EC|Vk+9lnkLzk~6>!o1DxT>^Bt8fI9V z*u0Ugtu%K?UBtOS)rB3Wn1=H(ayUxqYV3D+bowI`4HN5@{w1?@c;7I9{0$ z)Plklnt?P8gbs%0s!`a1#MtBfE|@vGPvFHaDscRt)6TW;;SIavraV;s*ae;-=~p(f z=71)!w`4GL0F%9wb|Ur1Mi~SOiGFkY$Z^=s!1_(TPdYNP_ByUa8+g<-uGwJE=hg9O zna46f+qSyPbd{D?{dg6{_DZ(8B?aa9&65P}1Iih%eMqqO0}`AN)Pe$a;P!NjkN_jt{{Motx$r7ycE`jOVPv=Ib={EaLJi;7icTzwmEe>%uF(82+*hl$b&)Hyw> ziz?I!#nJ49;u`1Oy5n+fiQ-s2u-}>;8I!H)+n~Z)-fb19D}QfJ^Y>YD*2=@NYs~}i zee4V4;YrmqdEuQ;HHVSs*2qw^m7(xDFyiEgL@|5()c+%qU^yF|)I3?WT7g_R2-FFA z4JO-d^TDs*o!TdU_XCN$lrANOa4_z0C8b=dUOCyH>hFqXi#CIJ^G4=JOGx9#BwW22 z!okxb2Lio=IzUjYAb=V~3y?6t00?%&nc0`lt5pHzEbj;l$)y{@2 zuBcX<#I0T~0@|r_0%80p%8YPxKo%l<{*r>?xe`(cjm_BDhJJ%<^UVm ziVS8Bhn=3m%;B)NXE1X(?2HU%4u_qY!OY>Xvoe@D99GX@<^U$$Ze^yObvZi=Gl%0h zGMG6W*34k$aM(LCm^mCak-^O2uyZn)Ie=BDY|84jvhQ+t{oD-493Jny3}z08y)%QE z!(s2rVCFDb@^Q5(%KY6~m^ldhavUxutoa@SGTGoN0JUeS*9k!_C|t_`7_Q@ocFBI( z$3(Ax%Y&k$=sUA%FPx9z3;)7_iM-Ej8;x!>XLVY$z7_oi~6=WdQQmBPE+y_wvYYl*kb<-W+> zqjF#3?h&~!l-u)^oFc$S1PCAIcYz(-9}d@3Ce8QeO7Cg{YtO0l1ht^RNHp4m$)Kix ze_g#sSRCFBuB#{JQWtR*X%S&fP;>h1Dn@NS#y(Kde2V=Yt;J756dW8rDZKxJ^C{tQ zE~iXp3c-9X<1>p!bFAO{e45^BMwhRQG5^4j-SP4~`5NEVc)gVoXs%5WW=`L{m=g(p zr@BiyjHaVw%oW)B-GtMudb^egI0}E!AUkulZ zZCi^R3PJsGB?qunD197OeB@oj4)xCpa?!BZ_<#zXD$&`AlgL@){Q?vk@3YFdMTz*B z+hO~*b8XDEz`8K~x?3MwbI^yyb6hv#hUfB7To+C$vEXzpFWDh)^niV}6C^jr;U*GA zhQ67P9WAtHoRNaxA_?+EN;}*_fi=&ERMtJwX_acfRs$2%g2Jsrx*&&yqKo@Gge0g1 zh1)>l-O@`5Du>(gq#as$=Iz*&6%=A6T?SYQcYs27r`$_=n=xA7%0v0I){)QVP#@2x>v$ zZfC~pr)2NAZP2P8PRCjK8xJMpq4~iaL3ADIwXT9%P+s0xc z%^k8pG_RF!$7^!<+Z#~62>dqW@y&_g3c#0W)2+j$S!?(##WP74m<6brXo&a(teOZp z*^E3xdjvFH$yf>Jg9!g7R~{erR9&v5Z~uwVmJmZ>)4R~CS_3WE zA&q1zAYLs9YKX~ndAw}K3n{SnXOXdYd;g;3udw848$Hoc(A`jUc^@3Qg~o$g>&1WPU4s*afHG6wO?B5ml-=4|RBPqJ}P#4K>-2ks*8HI=bD% z3q~!!a5vn7$5@X_LG0nMgNWxB>K;A=j#;Q5nWklv$9`D>gQ_w2}1$O?_+kY;= zKLlWhV>H~S&gXr(Bie*?H=_M;g7O*AWS|y)f+KxCRQ#4|HU+poNo|<{FWOjb?&P%1 zJ*@S2@^x@mzFpa1lciGKw8DxHah65l%Jpb=0a2y0d^5!4z+_ihsg+e5HtT{n5`rCk zDeS3Gkqmp`3a{noS_O6v%{~8%d{^qn(g^J6q+wxi(1tEJf*_Q3%pWMBF2tW=XLiC|X+S4tB?HGI+(Z*!WL z0x{i#ISvWWlAr3KP_U5pUBL$b@H*g+uLJ(dI^bLFymtD>t^wwSLb?xcyw+{F_*8#t09q`|;13t{F z1Z!(2hpYqs-gUt5Ssi{LLuD^rD0K3}82NE)rFy%>&PCV$t)ZzyeJq95qC&(TeJD9h zXKu0msAT>T;thnd1?sNy23=Kusfu90l^WeZ?D~#OFA!!BBUJc_xsy)|>R~6_BamC} z8o0ww9e5W{g<4?`EY_GXZ=tEvi(!?T6uT2UL*mB&mE^A=vwnfyw{YO6GxER&P* z*VG>D2z)B<$B|k%4ciMoYEb1xyfobCf+ohBzw`H0+Vyi-r>XEbv)l_ACRMERx zMmhncnWB#+CRzdFj&{qFq`UWnYx%S8^+#oGf6`~iCQ;S~S26!AOYv>liF-(SM%HPr zBW@vfl-1+SPUF!BY{<}_&a2@^e**=0=0C~i4x2-Q_~wvKH+lRE ztHs^9%B;861#c7TTGjXD0P0&KdlXkPx};(a>k3tl_6|0H#zNBVuuDs52FO z+~`?+B2QFQt&%5@OzdwRdwMUEe%dArjVoaQsr)K^5Enk}Wnm!Z4It{ibA>uWg|?Z%gIIM~Q=3_UHBKXnaAR zxbZm=av`|<8nms`_z3|@c4bT=>PKsYxgX<}^8Bxn%P=xIofCjKxx8sd-El!rR(a9dfI_HrV+v$~5C-akvYw~K6@HYwq*`Cn}(>}{meY-L|X zx^Z1)re&QrmcwSod+kB^?dj}DzR0(;n0#IzOg&ZVu7;ukMOZW&;8G5YBoBikCA-rv z+kGKhiN08xKTEnaw{hSc>+d7-_S#GE<@G<9M_Ol_Y43z`qS3gp95(l6*E;99{`%2|N-w)}ep{<6^tdzwYj>&2t_SiCF!=#H*582ReN25UFenqd*;v zoA}r`)2VyTqs5|I7kc#?2qgEiYGY^ZeqxNDPk60LAJDBKUse}&#Ls7lnNIcruzSj# z&6^>UEmn_JG0&uWCIq#h@E~|$5SZ&^zoaf&URA28n+*XD4+&v&e&{4()VGwo!ch?8 zQop+Lkd;{}x(5En+Wfx+TZQDlTn63=LaBL6jw?)VOSM_zN>B?550f5;BkZ_BPpNrp z4*mERx}X+h=)K%Ya3Dp$P9tqSBBn!UW)9u9gYJ#gImY36P^TQX$5SXLe}oct=E`vA zj6yOS_RLhhQ0_|R;7L(BlgH5YCtu=c$lu;9B!4C9Ru7fDoC@J+`1SIci>(}cCDHcn z^0E50jj3FP7n--_@_T~vJ6FXcs0D>bR41R~C%K=Z%{PHOEwzb4^Y$FAw}{pY@HZi- z1qEi*(dHdFq!U{S3Ti=XPf(TXyK05zojC$0wNeq(f-DvK^^2t4z4#c)xSagji`d$^ zNOdNUP>i!KVAPn)sPjR6s~hg20Nt=;C-2V@uxrS}wze?cyJUy@atO%-6ia%H_R=+v z(P}I=o#8*D<)=4~*Kvy9)v!;R1Eo`QGBR(L+M zNoHYMQGrQVbuFRfn}UsXJ6az=cnEK$2A$7uArvO~nxD>9@Tsa`bV-#7K`kgeN;4|f z26U)XatYpOC+KnJad|pgeU+hwqmN(Hr(D-(!K!ix1AXlXhTXa^`DUR6PR^J z!(;q#pQ~;I?#U%rYn7Ft zP5oF|1rA$qkyv^ueW@;bYM0C&cg1$?So1SEGRsBAdaj@rWNE4Wpx;)D(4H1Mh*)-{ z2PJ^Zue~G-=c~~Qyn@+;1iR%~_1|eS;S%yUNlujkwhJ2AWwtM*tm>Z7>>{$6h!kg~ zyZ>#2G*UPNj#1H`#V5@da_hY?Z|iDv81MD_GMG7lNw-Nqw?F3xat$Z<4t+YpIijkv zg63zl_~sxMu=_KZIUM#t1~UgRwfhR+U6gOE2g5ttyj~L5*nzDy9wbu6L*pTNYWJd! z4j*t-r6s8CSy$Ngw}0Equ0NcmXAaU)*xW6*iH@dV2?-R*!}y!>I~uJB>pGNvgccM8`z>PqerO9hU* z0UWzQs1|};Mu6MtrvRy(lUtQTOim#FZpF}Q+hZg*5){5fUyw0(S8}d8(N_9-tfeE7 zq0M0RH4KD(9nD85)l8nb6k0Vl!7CGjT2T11y7G1q$WA%>1~FN=0BnEpaeU>f^j_Ub zHcDykl3OfuRu$C5#YE!_0}YZf)7}X|RjA( zcL$%b<;t|X4UU!5Ex^ash06<)+i>&NBfm!_xAR*z_iT1{=!D;*Fgzm;p0#8cu%n-U z8FYv2H(&+e4`qiZS~0AjXpckvF#FdSt#!oi;<>I?&XtM@h69!H*?@U_85U|c^TW2H z1(y;`32ZT~epls<1yV@$8*w-+^9+v6QifOqr~BFAJcy{zXWgsSN5qqKk}Bc2{-}7+ z!(28eO8#bqj9vqOL&#-u{c{Ru(^l=-=O*Pv`;#^B_5d%PhxezUq(Zl~!Q>9B&xQ!Z zH8w^n4W;E26L#53$>#x9?0wx*!i2$bz;dp+EPQcIdp746K1`0-Ihy|_-+OHBv4v}u zt75obxwkRtF%q@0&m2}p^)F>Ga{$wwG>9M3p5({Ri?gzf!*x&@s{pSaNABz-d-Y^o zSC@w3a1DWGYjSmImTBXzF3nD%vN~a;#@M5^uIaaX-1bs=>8(dJWn=q6xa5~#SV~KF zG(d}PE{SyePs6ic|6ztLxzt=+)v|w5-&g|jYe}#5CQplS_ArkD#A^mne)V=`oPVxI z?XF$Ew}L|BQCIQu{d!iG<{(YR=5J&$b2#jq8O$8OG~evacPTusXZGg0ZS%COc-2X* zcd2+UHYmlbj+#Q}RPQtB+&HMCPb%+hZ)r~RTS`_ueLG9v9Hg7w3#xp~@yA43-%7#z zZ8o+0V{wa>%Gge7?WqzRqInm*w8O*n2To>m%b;>}$9#r5w1$ySow zG-3U>As{S9&Gb@`GH&cPNegwTJ_WM{;GUjNv%}t-@=PUzCzYIw)djmGF?k+*M%O3# zF!Rns0_^50RpvK;zdaU87)0YL64(IPl6GG-3|-)j`kJM+*$z*cZ$~OC~A8eYu*FZeMt+}e*tMt1sdor zAJeB$Fl1mdAEP-wzWyKiSiDgV_3?G`lCu@|@kb}QYZFn4)vwtFYsT15JaVsQDS66D z&iU^)`|7@q*n%I<#!G^A zH$m&be^m>o5VmT$*Nwk*3x~snEjRePuEvl0V;-g&S{?R83R6E-k35jFM1a+3VWviA zXw*8A&^#6NREz3!JbRO^zO^mP43ogQyaT~_;W+ox6AWdU6!|-~mhGTDA*clfw92D?I^%`h$kq6+jezP)KdvU&Rm62cn%~P& zdr8!IIH58js09U-<1UlR&ZKDiDV;%9;mR=*0n zh%`e3$Cu);t312$(_Kn-=TlDTl%vTWIK4eEpYAEoqLqyJbItlh_DxFB?yfm9Uitbg zpb+)~y!?4aZqrHZL)rvpa$?_}*_^Zz4WMuN6q45xB`jjUP&-KP zV&*y#Z|Mh4g7zV*)1^SAAK05OyD0nc;p%63I3>iVwjV#?TjVNyn;%}|6=ro)mWw>p*ff{Z3xWwHzsrZ-5W>53De22SJ0C#=(57 z?Zod$&vg#y)mF(R%ma+Gb3I#Q&nr% z&P>KDcP2-H;ddlbHAqWQ|H5eI@zkEy@~;B2Oz9pCme@LmFLm%{KCL=97EkRse!}<3 zqwejrvQz(&9t895=x}JPs5}V)6vZmk z-ePs@tQu{mDu&Hfqqf&mwC>Z}=>n!*0O&k%xzmuBI<8q={LJR?ZE;RqSLeeu*9-3a z3aR5w-U4_zO`vrb1~zv>9b(aj&MHB*P#H8a)bYBuB+z5Ay-ORax#+!FpP zrFk3FP6F(GY(Ec6QS~6!C^DVzx4%&|ydpP&Bvxua5`m{hU#q693Xh`-JN+uo6em5S zZ}rw4_0EchyxuzOj{hS?cdqRRO88beW*1%V+;Y#V?%#6HuGU)aIn{Go?plmSu^>xz z4O8i!U5D)(ze#EMo}<#ZrWI$XdRxoAmiW9Msg`RSX9XtRAFDv1jUA>2rdpDwrLkSp z%Tc6LI~AbX;AwnmgH=AECikk+az3>c{3QQll+^ZEL%_mFgzWuu#`ZO2ZvmAiW8E+0 zq~ABp;jm{jm^mEwQ^B^1>p$b0yq)9}U-Q7Ze2-RH)Xo6fc!qGdsH|ON6H?s3Qn8q> zrk{qbmgK$x?W-ZW93$**{t`zviEczl?M%o`2x>v)@D$l={7jP@xxQHQS{;nq*-BMh z!I1a6ifm`2W8evW@g*SYjy#OxSg)_fBD-F{0ABkrNIjk9#xI4`5u~i;x_m{Mq*Q(m zK!+)nJ6lTS4~Y?}oKY$(JT7*wDt$!228;zH#L?z+xvXuhtTmN2K`ki!L`cu)kTwz0 zJA@>t1%+ooGOe-|8E2V$o4?9MSL-8b~R{4gKenu{hX6Y%c4u~nnlNZ`}qV>)P8;giE^>=TYWkjztacVMoy`f68zt%me_;GJ=+kzB5Hl}CvI%4OpZ7E!5FGoMuOxdaEKi_!2aewx3|?&1JijpA$Sk?}Ci-^KQQ6=RNwwjra0l zf>J(ag4<&JeZXt)=Z6WoTvwb_M(J+bTGiF%3&{tJL^mXcitCsp4diN-j@sR%=4G@_cO*`qzK{IY&KJ^)6pU@V&@PTCG_i4@ zhQyZVuXcelLHeJJo4?7G@n$OH3kjPL)PlmVRmNJU-vj=M;+Gq-jNiYD!@7-Kt4d5Q zrP>FT_HT#~e#;L>X3wIfJ}sr=uqT{aO4yRo^oBiU-RQLVAW(QU>Y54WIBBhucN1~U z>^<;Y1li?HqzBv=D~UPqxp+2l09*pVOuF@?hCIoK`0;C$`ifjox7GE$dt`IuNYuS; z)DP(?%FmXJk0&WV*QNP+*~|YGFaLk&L+k!$K9|@3ALr7_UeCv2$oBs{tKoMP^Q5en z>f(Fsb(BqK^S8OG9Z}VqVqZ`T@&i>bL8AG)9OkGntL#Bd2x>v$_aKdQh9lIWyeyYQ z-FtgkO7E?(rYgfQj*bSFWtq|AxU?Xr&RsOj5lOTp*B~>aA=`C<> zr+dQ9Hk7Ah=X86k;IuX4gd0I)XTvDOVO!`Fl415L%Hak=9PXCU*WnLrjgQ*ZZ~2gG zTOk^_wD~7~ELNwHN!zaKW-l=Gx5k~$eS2lfVC=bPqB?NZhnX;=L}9r*sZbE;cOem* zSHAEch^-bY?5aqlzY})j$&Pr^9@M|(22q{ytx6do|J_ap)ORtO*LL(;OPCdqBq8)8g)^- zGaVm0C~4L(MSY4LHEhI6je_cYVhN_x^Jm2FgKlj3YNySCiM20p5>V;K&dWr z<*>V2L(EePOT-~(A;sI3>T`dD9{_g=aFqam0?_;m^t08*QliwZCTK!X3krV*Df~rQ z@qCn`36fi`eB7Pp1JiWLES>tqjS?TYkuP`5OC@K8W@fJUtj^SDCNuTd98-I@m=d(9 zA7d)z$Jd}M#LvAcKNV+$8ZBayZ8f#3be~eNu?Iu4oNmJ31Ua4fUZ%xF=O9sRXb4rA zU!yV~BG2WqL-}O``Bq5j&Bn?Yx#9(iLT7RvKI~{~HxYzJ#_CUf(#dp|lj}k7%Ivb4 zh6fy(XROYP$qfXSlbeaFI9|@K7kWEH1jy=c4m_lsIRAM<4&9 zlBbW)0)ftrWqPq(m&ebQ-bgy>P}Z3{acpB-r=Rh;PcOR-oBLaDBGI$D(gthHSP9!n(?lmtyTVr>icOHoXG^06 zNwg6C5xS>J?w+FdIG&B^fmpsXmX%p|G#|$Fm*NzYO+jjTG^%+FFXPS#tz&d1WmmM^ zV^Z)u?KHOEoirz5#v#a%pWMx!43*}o?1u(M2CW{D8*V0_k{|4=d7%%iv(&EGFRG1_ zG_!p+rz`zM&6jCn$t{W}J&<@|yvEkyRzT@~n@t(v3pB~@#bq&M$JV=_mRvLJa1*4< zwSCm_y$m_Ov02n}BgG;a_YqLfhHmXkX)BsTgGf6@*qzRR9&-`v_Ibzhz%Uu}s$%AS zlvHcC!AtlXSSiv0hlRi6vxu4@4%9G{PTLKRG!zGVYhNZIyJEjF7l5o>G>JDjc2MjZ z*J#yOTvhst+SY!g%gcFhfQa43(pRht%fzm{EC3V$)&n`FwBp7tnV zbvNRKuR}H+KYW~lBt`-398|nz- zeOss$)$}if!0Siq_oWZzQBo%>VLg+#xp-O3EhsuC?Emb9eZtUQjPsxF|$Y~=Fo|8NSZ z%BR}1)~Wi-JtffKP(!+8N*68dHOdm{Fnezd6s>g&bso#Bc3=+D%4`(R zRoMlm;!f1gK;$*HsVGSin?UX&G_YJMji;Kjf$Nih(-v5Bc>>Wl{4{ z;+p+_r#((@Sad;MWoNkd`dVC9Z5A>2|FF;pNx!ptVwQAQ8?j)wly!O}EL|t%r5rs+ z#P^Yx+7nhIg~k@DieiH%goG?lez=Q`SUZcd6|Xc4aFUHyb?DbVqv1(V3kokYwKa=5 zq_c%|uaE?_pzw;2I&w%2A>Ah=K`ki!10F&fU` zC!M?cx16RsfTQ=T4%eEaa*pCVMDc!66ttx!(-8rQ5g!HhG1ht?r1tgjDjPhs$+l7_n5yIW+ z5B6~zBGKZyx^ZERhYD#2-Vb`B<8gmra{GQgppvyOzk)8E1>K;*n_@W`W~TE_z?h+i zmNG(1NS|NHagf~4Xx6?{XzrF%qgzPieA3M`>JqhfswP2o`wE?utzRxIUm@nwE_eu# zrwU_|Gg{VB)xCK$%DRy~V0d+B?Q;}Ow^`*3bU(cvxVW>*bqCNq&|jSz+75 z8eM*#3`LjbaoyI~vyICl(28ocXuBIIPGltO`d(zUM@e+#^f*pFkHZd7dqC)ea_tKW z#a=B=zKAP%j32*GBl!|e*Ap=KvyW%tqM@;VwKTpg@G+$E6&$%VYF|z9KOQGv!FX;9%Jj?AAPv>=@pp3=$uqANe+e-G`*#(#4-tT%(11DNI_4NezmjCmhzf>A$t z7hf93d-Q>r+Fd5AEQ?p(h^pGJ>i7T%*U9TTLM>%3RQoVnv2TcD=15;dk7oi*gUef( zrF0HfYx)l=-S4Nf&8sx1tt$OM!-s_A+W92l@&$Uhf;!Lz22p@DMBK_PoygLuP2bRZpXPAai6!45l1-y}_VL}6xo!H# zD}IF2Wgk7m%+ue-dv~OLgGPLUx?9&4Kb*sSEkmvrPAQrH~0rCv;mwD`tT^0-Bnp2(#j zeI6)AXx;2@U1@mJ7!67pzArMIffS9qPAygCYpThuA5ojA8((@eyOO*_ z`Jm{@L4F6s-f@iU%1kNgAS=mFMQ9Qpt#dT_c}hPWXMQ2?qLsH&g)N(`X9ZKan}b~I zZ87Y#ZqJYk;g_IHw$Hj$ZORMb|JFWB#8Wx69PLQ@A8nOEA)oz1vPRC!8n%!>*{`({ zDyTQ+ba77avi~(bB%@IuS2KEl^yZnii>^o-yN^L{hw{8(~@3iyq@3* zT-`NG7pAvOg;Y;Ru33#6QY#~mPil-W>q-J2;flKYwbJ+%KUCuj`V<>4s#v)zuWsPF zLF)q6er+K(@BBti#(RY(mI(Qi9%OgEA6L0qv*nTt77l)5rMhvh(bs-UL@bY!-|;Oq zHln-6ab2I}B_NHB)qj;I(lF@nfigsJM~e9i$sZih^8ax)|DRU#|JnT+y}!7(P4BM` zxXWJ1U;v{2FrWJgpW5FDLNlYkMgB;}U{Xoji)64j5bz0WD`J(KFbJy@lb4B>Jpum; z?jF4W{|_8|{>dl#7eCp%%xilBzEoQU24joqZU&-7ySluD{E`-eQmXx1NYYX61Rs~f zM{`5iSfhDGMa`ZbvnA#g6AHOUntI7K(#cSH)wE7(wiS0HBhPrQHG}d}kCMOf{MC6aHr>d>#t!cHfPl?W? zC0r!DF|voRtn9L9MW?_nkJ?MwV*IlOzlgHu?r27Uy?*$N6aGQ zDUfpk&s%`@%~YqVUyVhZVF*BTQ7+btiZw&A1hpVt=;!P2?y}iWl)VJE z$VK~giz7js`f-jB<6G7G8zET<3fk0m$6&fm$=Y;=QhR@;ocrk?3*OS?DGz z&Cwi_&$n_Ss0Hcn!qM6QoTz_y+gJqoi0Cr`jx%|4QJAz|4ya<3kZX(90BeI5-Rhn- z;t)QUf6Q6^1YD&j?+0!COx4R!oCRt!o1fIFBx`f{u{mi{-fnB>ZCSiFE_6>*t}MQu z$Irp7FL@aq$r^Zac4~8#HhVhj={t$uGkJQeMYB>+`IRDVs9Zz+u6%~RU?N=g55#QE z5-X3%;MX#APT}-1J#0b~iOaU!(^*{kL?+pV^~J|4ljMq=AiWkLcLO3IT+Gv_qcLC6 z;j7d3)vi^$w>HX8n5$-+juRg5dc|8vnBpzsOS~=k zC?2FMwO8>I*2~4~vU{^`u>2T**kQMME+p%NyZje$i)5}6DYc8VwiSL)pLO-tc#>@l zqI|@*hsUa3df;sViVa$V5qf<$P zg&%fM&nnxcv7-T$Y-v5FHKsdP{F1=#(%9}m%4Xn>jI<{?8QTg-r|ah0f`5Q+U_`NZL*xSos~YW1Y;;n5XstJ{Pc9fC*Nc-S+1^crQ3xwSqc!F0d#?t zWFNVceff)fw$VS}ZiPv=%AvbrqnFxgW&WkGcDCpM&vJ zgce*%UXM?AFoZ*JK+R60QlOw>P8)&ZSOx}oRjFOH@$MttSJuC;`4fsO( zNCFpL?$0w%SvB|qmF8Q}rIEf4n~2^}6|-7UW3oCJ zRy@_!7K*@Myz<3tP*1K@l^+Fa4z`D2M+3V~cs@S;*v!x3(Xb_4cf7IUe zR)kJX?F7dlk}hF87MO-^xM(ric5PzzTdZkYud!oF3w@9|WfO?LB5W$6q#<`m-O_n& z4(v|qzeaJIY`Cvv!(wAU4Gm!dm<$b52s4BA@LZ-xRopX)`)T41X!||}hd$LffQank z@6U%lDzjQsyDbLR1gX&$+xP`hJY3qqlHH8&`}-_D5m$W_VvyE2)Z1k{=;+%z>mohL z$PT*RH+t;+;a%{OrMWF(D#9(GH_0wxY_3AwGSMwmQftMs-<+&Svg4z$MEiIzM^~|1 zkz(wy+{2l(=0iR+rEJYvcf$vBR=1UC+&CDveXg*6++$&<+4b6eub+XRl#|KDC0iG#R5IgEkai$;S}fM>yjaY#is_z|lPVa)sh+B2 z=alXheQWM!!WuSV%0k2lfiG39Eo$y5dV(E}xV8mMs;xSI{{Gp0#4qTMaaxSoQ@IrD zuhtmdLfg!0b@Qrp3;bFNQe&VjVKe&2$6=V_)QG&XiuDLBu@6uy*V=fx-Cg%t@je(f zC!9Uz5}f%$Vz9e*JhjlnT@(b_o?3DOfZoLig2UBqZ^6@FWSv&kHhH>>vk+XZ4_)}s z-h-D5#`6!5{gx#?n(WHB#z_WHCeX@IHxy5V;==2Ed@QUQ{7Y+mEW2{P6hMuF>3 z7DmUVRYUEEk^ zpHf}kpi;5`F51M&@U*pPz7?8bQz+53rmJh6B0vDp+$ER(Ho|?I(ihZ%!e;8BXL$2! zweP>e%R}O&&v+>`xR#M2K);r5bJrZzZACQ^RY5H%j40{da!A_==~N*JYC&OCNW15d zUM-~4ge0g1h0TTZnj8{#Z=6LClAsn87Ah0kLFS;Zm~3w&>y6zRDv=s7lI8s5s?m|x zvZ1W{)EV2mDTjyEZgN#`UBU+Q9B|UEt|UUg0%1)Xu+=wsb?|R38@%jyL~QUXnRRUN z<`Q4W{%#<0G#vG86_sva=!$U(WQaXKH3HwVjS&qVlSYG3TY@ z!Q^prQ;GQ8o1(H}U78zgZHluty%BLgr}E3sZs~9tPNH{7z&wpFoi!UvPJ_Z#E z?I#Ni(}tvR?QXRY-Z$xy6hjypO2_(+XaLkl)s{JM!)O^NE3v)Q`5|_2m8SMfj_2)> z)knnI3K|Q1vEDyjF6~#h2hG~s1=}f3&fseUr&h@9HOrqI$e6A1hqz}74}FYMqD*F* zT_-`XZ;2O@x6+`)4*XDvZSfbIR51Dc#`-3wTH zuC@9hhAIme(D|t^&ElBDc&zW8!OY>XeKMFifN}nLPhbm7%p9&>18r7CV(BESK91hz*gP8+Z|CaOZ?zYcUXVuS;N;rT-+$2c{ihq=W{1gFuwN<^@ zYMm$!+k>0hB@I>oAyiEkaoD*HpH-c`cMHB_8$P?bSsT6!@U$3B&Q598wx&zSXzukw zZ8OGAHq{mF*sp0(?HsCppbb}XIi=2&l6`vPus0z-|Em1Ds#j(7tDkR27t-pJUD&e~ z^K};Un^{aRGCKobeWp!B_|5}|F3iv(Euz=v0*o!2O}m;0P(#_;;`PEgizYoGs0D?~ z7zomH4alGSf|1*c+DP}#L|@Pt;QA=lsIMAo2nYz9?Fvnvq^eR)YpL9>Rnu#m7A;XX zAxIVI!b_t507O-tLezbLs4`Q?u0Y~;m03E-728o>rOtM}<Ii2AUeGcs*-&zE;v5^_uC%wV;Zk7 zWSnNawrpfKmWl1mEoL*fSaf&t0ivlaM33>9HL#D*UOolWSrAO_H2(f~d(zQ;Xt0_6 z!9lcoG+760&`Q&oyX9cC4Q>2O%A>dO{T0PFcUegxm5jTP8IFWYv_BFntEYiu9WQP5 zY@+uJ^cIo^#mx!Xj}rq?yeXd^GELrrYwRST@=OTKzDsBz z+}X=|eWjtW1?(iflu3Viu@r@UY$D0Wi}&F$=;PmnBo{t!myP$i5D)MWfKNf}?GR(7 z@Fq}A@9&zGa##kSw~J)0|8E0HI1{DuW&h?DNUUyP)m8++jTlYfa3YPk9olWt#w-2K z@;Evrx^w+0ih&F^&CW@E`F~rsRz|Ge*h5T9-Ak*-juUrUS@m+cw3XBnQoyZ(@**jE zk#L#4ibN|SD-zF0RwR>i(dor?ok@C=A5xo?zhk3~-;?EUr|7tATn>}&UF)r{kiR%N z2S(WI(9()$LHM5d5zSzxg^^p)E2@ey3+iZYzx#+}aO1a&J0WTV)Qn z7F<^YUW+BA_U1kck*^s)YiXyI@G6tCttPpUoeJzOH(w96Y=$@rQ0-iDG9jo1g{_Fw z)7d;Ehjz5k&J&uT7Sw!0F8mmUzf<9YT2R;;GF}eLa+z-)2tuF-5>~A)+%B8ib2$yW zOI9UcvY*|H@8infY7+vt*0*MG8*B@Srt#!GFi~1N)D}k{2daYi+q^Lfj)ah97I0e;f$n^O1D2G+TBbNPJ|usx`7Oa-Ilw zI6+Y|{5x8~=}0sQ|D+cFT<(jU#-Q|dm4j3MdMhfzI)%xN47?3VjM@jtLD&vZca8H| zC>N3o`1CG5A4X9CT!=?gR&pxH$p_`@u-?XCaFKi(gG8vmT<$B+=u9pKXgdmhorz>z z-h0+Z&!JZA5)t4g2isnV^bHJ7$%hCXhNO*7*ZP3c;R8yC4=C{RVUWh(q5(&$*cs>} z80u1eZD;dPiaKkiCzE3BBcM+RYC+-E-o6-!xZkoNY*w7ae*C?!OY>XH)b$%IPAy_W)6of6HGdiOYnaa zKKw|AEn%b%yOc6YKFUu}cDtL0fnS~xCzq+H`-xKsAH&(>0iAmPmko*%d5=RKo`*Y= zPXMxe4pQy=HHR`g_jlA91ao}0E*A6*x8Wz3gPp&>;9HbaCL8QWdfyU{m)^Sxy9f7b z+~~TJYxt%o$JTNWuEvDy?AZKGeeRgceX6eo{vBvC7?7#au!FIhpjKpWL^EhPxehl6 z^OEcN4yTj*3pQI#y8N@0+yFv5oq=e>ZL@Sr_Kx6pNvFeKrXAOQZlNQ*ixLSKC6p>1 zJU{yoy23RT9(D#X=7?VJa5m=^qAiKfHg;cay;Q$+yqY>UYw!$%cK+6v#)csW{XktH z4l>^)6|CC9T=e|I#Q&c1om8}_A4FAM4)2DWo;4Xj_1G%A=|dS09kv($eetkC%EMcf zcCm3HAB0YF)!lrP8aw>V6F)anK*>#3N?Ci1X;nWkJ_>A}Rewt_Z@=P2t4lZ|2APu} zIj%j_!FdO*{E9?R>V_w67*q5JQ}3dp73XI{(JXHLR=nnFo-9&Jj8t!% z)GQ;#)^MIw*U+pS;jVC-2tSTkF(D#Gss44m<|+>)-@x5pZ1O5Waa@Y0!FdO_Q*dS_ z6HQ735vk3uVp??PS6-%t+evo(MCdh75oMX?ZZNA&*jd*kF_~~_Xeh@$gM+buhss5C zj9C3nm5aQ6Y{PsS&ti!{X`*9H73szLC2BK0l*}A7$Z3djcr``tdy37si7{ahuI!}_ ztajQQhKp#3;bML!glO1$0<~f;E_=tBjv<+zXV+?ZUzPxOiCeWH^{cjh_fZCs>?eEK zCuu+Qr3+}ii~!nR?(!N9`x(IqdRGXe} zZJG{sDjcIkPWTi`b@?nMXe%X$cyc`*H1rMC(C>!rup>i>Bbg|PrujlRtlguqod{!x z)z&6m;UXBbpW&1oyJ@Sj==~+O3H3+nF9jPr(DmO7J(uam3+(*2a@sxvs(pf8$(Q~x zQUt$fzjJjAxiYqyfj?_t{rYo=HZdjl8&toJ+*-eGP_Pr0Ba3PuB~ueet3tjT*B$_~ zaV(xxH%F$gRi+;VKG1wK0rpdSNO;F75{WNr9)l}+7#Q3@G$a9^LW6SY<7dn z{ENUR1ht^rWAdt?Qxo7#mS{OpnNX#S@SgFfh%=JwV{b9|T?Nxg6ip{FI8w0h%n|qN z#Dvh;KK+uIAeXl{PXv(haf|r)vJw{5f@(Jcn>azlkp;E0nC>qQF!{NSm-OX7p^U>a zHuWmS?hcMd_VV0IxsxH-xMYZ79@GB+55au~T;F>0R}{a(BOulGT`>bZ4Vvy+YeFCD zF3_%~c9g>k`aYX~(mQb>4M3os;dFzJ%@=AfO>RBuxsB1O9bFbD-KtkySx>a6EB|h6 zG?fmWQyzBcc9yBSEi*S}I%aQsT-D3~W=9Uk=j&`={-n~PPZ_Y{wRKhVWa^SbXWjs`7xEgYVw!_&@jQKD z-myE$=rX)OlC_x(yk~L!JheE!VJq<;66BK$>go9El9zzts!Wyc9@R1CgSq}BqEaLP zJL|he$Te;E$XNzG4xdpY8L~SGb_eit;{^kpO7(Dvgs;M?UxViRGaBmR=360}e2t)) ztEM2R(Z+zVCqjm50rucs$`XM2&!*OECtjLmCorLvg(cta3)W+K1 zmV8z;s^<`IC_FCyDj>x}yhM5#MP|dUmBXU&ygIFzWvnciz3VR(w|)vBZm(t2_v^%8 zj)C0Vp7?A*JIi5b6Kl&`Ka-Vb7WcW;;(qi0ATFGc?%O7(`!3{5(iN0+m#iz@U#%9` z(*0k=Wvk2n;^qoc$i|s(Q{lC5!TN-t7SvGAjTq@wj4o zrhjCecq%wqxv^F}Og&S3`MXE7g#mJGl%2VGMG6WwmgHG1K84L0w}v$b$wYl zkj8|7)Va@bSW)#cxqe4k`ZgIy$XQkTmV7Jmg^h?5di3*UU}4l~s2}Og)UN~L^SFN$ zN#ky>$@3)7f=w}bq>B*Q$+NPd4Pv_1hHfnAwFcb+XEy&%izbMVg%!H$&(LwvsEq?a z1^p1T7TDM|Y=;)ZrHt)%makO%4jd=n8PGPeljy8^F@8I%4%n92M zUYEJc(Vh3Xn|(~{0EOCBD(D}<1pBYnS-BN&mCEVIf@xsazuMJIa_}1~E7g4XAHvap zT5}PKjX$zYzEYu2@B>io=|P+{{WEBvX!g%kGiBc(`~YzBVMlBEFHZfsFJ=#D{#NOQ zCxIg5DXN+6{1AWbDbi16mEZ3ip2jzr?811`ZK|u`6g{~H+*Nbh=U2+nqHUvT$HVTj z>cxzwab1i}K4(*~3vYg>v@O(+*O1pADPiR&%dc!0q%(O5+(O!h#zUppBMk_Fh;Fd+(E-IT;iTE)P-cJj2 zgWO~fu#&ytr*$s%l1Uph4^tMYv0z^C%-jwvqF-9G;`hsqM?4d6v$Y zDM}&vsYh)2f3}+c=d1aDv6}zc)%?F)&HvnL{^wWo|7tb=3+~VO%)TxDUi5J8o;3c8 z$*&E7ZMpo(Z#)=%g5+S&YZms~G%WLPz_6e)%hst{TcwRO-4Bb0!e41Xd|uI~5dQ3+ zzgw%)7|h&IS0~YYVGg5L=gK~ZnZsd?3}z08H8YqwfazYsK_r$xSYP@R>7?TB)&$1k zF97T|`#Ai~!b~U}vapu{jJr9Y;+d{*Bn~+m2N|A6G|Nw|Bpt))xs17aJ1NO^aS&y@ znxy)SI-!xQ{sO1Y_Ebh{N6_N5H!1E+Y?~KY^75F=;mPkP^Wl;oDSw_At;D9zBx!A*tr?Z91c4#gP8+ZCa?X` z#w@14ysXFAAel>0WUgJ;C3F30wYVm8{V(JG+2Vd+t?3H-pVGymk#V*iH=pi*i~CoL zd;VI}74$!)`?uBN=F|OeasO^{FIa23g8rv;UtTS4KHYW2<*wSIT~=E(gV`{kMnk>t z0lb5|EM+zxW;#&oUa151H)-g8xixgB2IhZj-Avoz>&Eu2Pniw+-2K|qLYVC>c71(1 z!jL}PJ~Y>pwfUd+dLh}jvCACr01Ro#VdikyMH$Q-4!bymnFAOy$@_q1!fxvgF9DT* zttb2VzM?W6Ku6QI03!Xl4Ho;plN>Zg(oD7#eR?UK*7CsqipMxe9amEfmSz zt@LuF99I9y#;eg(y6E_nu9Of;H*7KqXIgvgM=}*nr_YjN13c1S{S;%0u)t!87ug@z zp}PvY9I?KVNgEyBZgkl(sgFttyUVDOP-LS@Vvkun4`G<-sgmf$rEU8eq1(+zHg$<4jl+f?816ohlnl{-^;ztVg(CiOgl7qDw=$ z5|*$uac;Y26vJ+aW@C~Z3*jKbSOi!+RPDM;nO!`KX}freJ4yWi6UjW4?gRBiAHP1U zGw&O*@{{Wuo5O+nj+d?D6ogZ3_n)=l6dk7{>tmB~%Jv>(2RQ#pyxKV(DAuG3o&c~QILU{<(>G~MUzx@3^7 zJscm`B_^b2U*x1e{+Z?l0&BaZ43!YXnVpl-^qk_#*~W#ArqDD@&URRf&Z}BLCLTvgf>+}d9#h>lWS2w?}Kn)M;k>=n(B(mYc{ijA}Mfo5IbxN!y_ zXjq|6w$fF?VeN7C_oXCh8hy|nvUv8N;L zYd$Hi-s4QYZ{03}d~S}!=BJF(ePq|T;HP{zK({2VW9bbTsH5ph3pRHLUeJqRQdNMr z9RH-D(=6q(`EFV?b$uT@?Vi{hNhR!Rly{|r;gGatG}K?RJ1zT^)*#cg5+lIdM4#Pv z3tB3Jv6%aans)7P6mU3R#A<(+^H_7fEazLy`HGw;nUjg968333_iHQ!(mruFmpKUstjfhhh3e)%;B(WGMG6Wh6>Wl#T*X1E`yoFVb^Ccb2tp8rpGmh z!*0xA<}g^;TNT0DZ(n`)NbiGv6Q1-qD0LCuoZ_6I@7yi7*V_xx47Ho^8e!gv&=rT{ zgFL}d1;KfV!-mXD%n5H7UOAk>r=0u~ zjOz9*9&C<#ICK+6CO=y#e1Wmyqu5$lFjI)36Cgb zfbd#j6aZL9pCk*XGSWlQ^~X%X5J7#oXtHI$>Y{mbuB<1ZQu~gCIzcT+PfKE`G$uU+ zdz;N$a_Hx@&;_+1L+>u9b9h&DF3|>*PP*?#6X4C=q+4P%Br9Xb0w^?Z%~3s9RIS1V zwIHi-EC(A3;wghl*vq+UYaL%~4aW@rUWC~UaGW%C=@>N^n>1}*v5`jJZ_6cnUMn+# zT2NpwaI|@Q4(XjjdRzr0s0EqS+rFCy$r*u!<;qc{Qns7Ddyq)(12(=dAngBtRzTx( z5&(x{G9oB9aOI)xY3S*Fqj&}D0>bcp&s`5U9^w=>zeJK7caAbH0& zZ3?0nco6XeR3b*F*lO?KzDB}_rdPoMD9b} zy+H0m-90S#GIwt(_Yv+6av$mL5xI}SU9zrZO1U^_0CPY%8)wR$#<5bexnjJQRu>12 zHl<`#fTaNJ!NQUq)$qZ?0nIyd?dDxXsXfQibwW@J3O8sFQvpzvHh=1#f<1B1qAZIE zFKuAYH{WW6=Pnp}3gu)8iE@dC{q8OXR52wtU;W{_=lF88)tI*dwg1DRIa}@D#$i8B ztmYVwk*2)BX{enU!xCQHs0iwsm_v4O!pykXZ>louRH2wCovnNazJ? z)togGg}_vT7T)V-y3wk^ZCT0s4pkwUMo{z4T$Q|AJWK~VA*cm~y{XRTr*lZ}5fb;& zRwe|sps)`}$qZnbK$ebpD#TopbDdjaMAC>uorcn5CY zmCM0?O2l?g#DDB;Ntl*t7|#j^5F8EuO>%nh&`KAs1++Ej2ma%D=xBV5|5r~}u&8laxck$~;w6lvR z-?VdBAkqcUL?h6=JC~dH0jtecZUnWUA$xe#O#S*gu2po*`VN4TuAxI|qCCrXQ_7R< zWi|e-uQCivqh$_W=PSS{I=7 z;`TST08JhZEBbBjIxXP~n&$ff+SB3Zt6k`l@XB27*Jrleu#I&7x{zSP`Ig<|Yl)!0 zN$JayDNX7F>!LCyttJNFa9zFNRZPRrYe!4R(rjGL@_32UF}cMJY;1_C&g436=h@?M zK1@Sb_WXv*h>J@kFDG+ox+5$hUq|~K(q%u_$H{;d*89n_PeaMHEb?m15WhF2Ba0f! zycjKp$N998+Impdx}H}=Dy1T_(uHbZJTg)V2a;H09xh#OHJ@*7LxDRq_4vB25N!mV z4b|2#ggOZP+Qy(*1l}U3)D|eh!N7;p_PI2kHYI$RB)BiGkRGg^B%gNrCG;b4cYua>k>#0oVT8vm(L>sF-w@7sw=SYcBY@F*#4EZ`rXHQ6RaWT2K zho;DOsYY>D!s{uaj8=!~+BSg}w+j_YT>7I399a5HZWOpom9!aACj_;iaEOR_y>vx4 zFhVU5Kd%x$h3d9sF6|$)V71`G3?s6Y^cCggSCs7ZDeMT?P;Mt;{7AF(-P|!--M)u+ zIJ#!F``p!Cv+WHnBukbRL>}sCS8fNjdkIXwPP?|JK|82jHO`{|h8U)e+T4VBP$puG z3jH0fo|rch-atMWmOI8PFxpodFYw_B&W;1BJv&9GGQe+7`O_k|Qt`c0q-iCi&3kjj z^D!0Ah>Ay03krvdY`JLU`pP41a--luZtKb9?#q$;c#E8%P5n5z&dxD)q>cl^M?o3W z;MvzXbiq|qqPV}SuWRswat-!ZIu7Wo)HWx9a|Gz?3WtfA&c3qFIjY)PI=O=(F-*M` z=8Yud|N? ziWcLos>@mx_B>i2l>PRta4&3i*l+qi3!-e)F~Y+f#xIvQF^WgScFsNJJsmrw-_#bm z{`@XhLyi3i&GxkL>5&P(adj6wmhI_Lp>TkC+g!dbg?J_we#h+%y$*JY(}MSAIdXIC z+dvk3Xs1CXoj$vDSW>5gET_zBjQTspVIfsvk2Y$e+h|%8MyPbyr`(wu_%aFf4KY4i zYiQ-m!!{#~K0hgJsc%ZgwX-z1UqMC5eyx5#P0(~$=727+2QrvBEKS$zk3g5JY%td4 zev502MB3gweAL5>YYXpz&gLGjcU~-ZHpU!C*h0dJwu2UjyCBU@jI9elDRx=F(}2TA zad+1iQ8YcB)hXP`$?gK4l|NB6ve{TE*RYtP2^TmS#M=VWpDPXQo=mH#1*ghT_bPvg z?;_GHSkMx&7u)j{6+0~(7l!QQ4To+^Xh%r=dLna3u#C@+)%Grye9+~GYB{OFib-b= z5;hSlEE*f&;w&w0hh{09N4D%(uJWzh*L>YP9&LR}CVN-xevK{QxB8~7 zqf@az`aaq91h*!Y?(#s`hOa;2mu!pEr37_l?)|}!1(KKdc!bm!(Tw_PpCG{sHy@~6 zIs0Wx=baJtlBGZZ*!r1Uv`fi84zNYEVeIDsTSVUmndATm*dkhh1!ls6@ogLBKu3}8 z$hnj4ZfpzSAfh%x3?#=pnk~C;6zPKpQ2Np9T*R!-ElXk}j31+ztd z6=jWBJD--}_s+QCn+Vge7`FT+h}OHhlH;X}+)D9QAXVyq0hLuLSx6e;CZ;LVhYgH4 zr1>CSHq%$$2LrY3sPPFwEhsEwZm(l$_vBoOH@cEtisA|vUL=0iD>pB2ehi=?0y z6pj!{3{}!O=egKSeFkd`qFkELd^i{VenlTsbU`gByiw85vFMCxd45c;MpyHnz0|p@Rx5jH4KcTs!=3zy+!D6<87@n4tI#)_7G$eyNuNA zlcjivi(;!(E~ z07})@YOeW#`t>;D9rLK>FH|njL0JuE&+6UYJNn09czj22eM|Rytdre3%hh#5?eQ_W zQq*;d)ee_tsytRhE&Zg<%xWdRE&SPIIdQTJ4CKa}UGduZ#tf4@NmMxXVdjT;xE?ia z`@MFie>>6Hmo?4WdDl3Zj%H3w48II3QWCa23Q10+ z9Q-|5!!&>M(OfM(1Xc}0=*onk78F*U;s0P+uuDyn!vz+VykF)cDkE1yM{(A4UcREQ1Sw^xkVAISZV>(0byGc(W3{N|b2XWBF2V}!M~Hw{}!Ps6WI^>1xYn?#v{(m`cRsN!yOlewRP3&zkj zx{c@yne924AgvMIAnF*qnxli%RXtuCh=gK$pPQD?TKWg{xe=PZKP4#|3B>Jj&4xt|r zq07;9LVg@-5xFrW# zO!jm05_v96Q@PzCBe^i#iMiwtT*mcV_D&>WnsBGzZ<7y;??R+$WX zDPnR3Ri+$%mO3be@2BpWW88phoc;3^Qr1h0DZ>O7hSd`!d)@t9a5o3y^o2FOjdn7# zVC+u|x7HwJPZ(DB;z31e-Bc{MQ+tYShPkidRg(AkyHN3VBFy#*vkhdO4}X|nHYAVO0#=ERX* z+;$re&rw{)Tb7@5wNL4N3N^^)D!LWc^<~sSd8z&YK*QT<(r)Ri-!T)f;|kHL zA=*dCB;B6oN46rQ=12AwTIj&f(4tK*HV0*a_SJ-D4oCZ1LNkY>J)6+X;b_k#G;=uG z*AtpKplQFq6ww_iFM4)?^ZnmS`i;bIZtRB+o%0KfUoo!`V{WnYATt^w=&joF|msAmqpbJP{`kgk1wTrMbel8ZrUI@y`7M@jsseRGU zDfZWS;Qof(&&zFX2l@DBQlI7^eQ4iGXy$OV7ZaK}9PQf)%^Z&QQbIF_qb*Np=5Vy{ zBs6n4+IJJ0IUMbK3C$di_Wgur4rthXX=9I%A3ewBRxqLrFDGHl;o{NIT>CJGqx~?U znZwb3l+euKXg^M9=5Vy1Bs6n4+A9go9FF#CLNkY>tw?C*aI~K$G;=uG&k~wB9PPD) zW)4StJ)xPy(cVaC=5Vy1Cp2?7+Ak8CIUMbm3C$eP7>n<#t;1^x=-LbN7S1fsIZVyr z;xZBJXy$;%9wuhQ67i^L&7sTHL7k@X4|H_#0MIA5x<=jWq9O-oF=rMI|a*v%#KYW=m?#zri zt86W>;gH7e6#|)YW|b>>*O(yxezKi-%lx%_H1B^({0=VK3kxn&y*J^vyUNAtm1@Dh z(0*7}wS+6lQG6JG7UBHb^9rE_54Oa856^gc`7F3GNz*44xZ6gsJt)Ks+Pp&GFBRKx zIt-m+YRNEH0UX7%Lq zRq?JQU+*_rI}opUlAt$>Gs6hbbYi)MIq4 zC@rFq%!EE=j#gVrQ;eQ9hRJ>U^d{t!2#k`gy_+YIPdBE~`kiD!f7&jo`4V?f-Zs|G zThWTg%;MyED=fqT>0QSfyYn}7s@ID4GyxgZM_BsCK@<{MEZIF@3gbryL-HHH&7rrx z&^rY3kf`Pro=mP9Z{-4Qpg@Nzkf`ProJmSwwX1sH5S4rrX$`3tnq?n#f! zis*<_Kw!)F!uRs$fV$0&{sO~LNW>?2bh;=x2PBOn*#tH+NzGT}k}UPa@y9w9w4cyv zIu#TiEE4Qpy>!`KJcn7mgvaAW<%LJ`+jRb-5bX~sDgEnd>B&lR7Kjt084StEpztV{ zn9`cI`A*n2@w~&W+zRV1=?E9{T?-fSs5lk{w;AqKkx%2nO(PaM+@EyA(?#aHJ&WZV zt{bQfJgQoYu&7@dxECi^<;Zz6&X|$yrsF3OEetBVKSEwOzP>A@6YsbizBl zfX9I8aIRP)+D=-xpp+5AGw_M+-(zniZ?IM<&+$HroqEZ%pO9gT2iM}8k@ z?m9cmc0%44GVTf*MOSMaqukjV?FHT0u57ibU`W;)V#AgLN2JDbn{8W`qGOcpN*_~~ zUMF_}=`F6j&bG*=dX$yenvCi+A@8lMxND(jKkL%2xU?%S?G;oKTD!Vf+m+^=d8I9e z!RiScR)HyiaRW9r`c;H}rxVl`?e1-xKl|7O&Q$QOKhdY~{t14c8$rh&mA4!8^$3&? z{~k0fax%_lo(H%77;{^rwqAoYHPjpBb5>3MB|E!x z6#oD99E(f!|8$Op^BmDZE-P_fI&BW9VKULi*pW-*~J&Zo%xNlMuGPcG6zQBP4MQOzqnODVsb3$#dq7Alaa<`oVq(8^q( zQx#~D0*Pu~VO7bqquT1hS>JL_>mJX>x3i`3LDkV>g)EH@={nAH6f($#O!^&`GhE-+ zqjrrIIneHEwM`gwCL0L*x2V~!xWlLATR&wTQo6*hcGlV4134Lt^X*Onx{u=<=@+T1 zt+TB=mN5GucD6NrndotJJQuk;8f5G{Xy4}!f2+B^HSI)KI#z99GW#Rq^Uw>D@O;aX zFvlrOal9}kyKnt?wSyhvc5s>6L9u?hemK+i5&io05Ay@aqPkHgCPgje%3zMB{^LV) z3XK)>rhK?GPEZ;<#%U}Q(_;M!{gB3$`t|F>{E&vIZo4OGSjd&Z+*}$8Ju;0@cR_k5 zlE(ku|7=F>xrLSq$Ux4%L{3TQ8F{KsmAR@@b@#w{^r^aKP|@AD(oajg<9JVfJJ*HM z8p>(gA)8{_ijcMrC5p{22A>ug zkx*jFR7Zv>jm@1tZ~nHNBsuMI-Hc=~r#isn{D7*)n-99hSY9dc*T@$8(}h=VQg%4>M(J#QE43TVFUu?d=SD zRjjVpl7;@pdz3BtESv_LYNUQwRP&0?5HEQj%YEjnl54-X`H~_Bxx3^H{uM>b?@r4 zk0#tA%BIum*mMixS*_c+XU>iPeklo< z)jQOXGc7Tv*R^K%DAfXD45&)EV^a(xnd#DMXJw!Q)lBi&jz#M<>k95$B$LtI^N}v) z`w6Grv0YALgU^!J=t+l<+S75c)1O}}D9r=p%tfz$gP?VJxd7z9q5N~qx)MEwUrMfv z%%SQ^^mIz@iN2h=$%D$Nxe2jT;gtS{{GJNN#b_yU&wh>Mwc4hF${5g8uRoSPly^1ABgHNpH zor!^97@0HNLv4%w+?Dd+j_m0(VrfkO4nO)9d9+gkt%GaBtR?&qd@OdZP_5cXiUR6L z*ic}Xv@me8)$W}D4yR{0>;xl+gRQp$0fq0iJkwO~V$aU_dFCcVCre^dvUE9>r5Y={ zR9%|g9y`yxGqN;~Pt&v=mn>B?FLtTYHQWjfPHv>2UnbBuV7tqZsOA+uCq0`FK*a%F zXfPN}BV3+F5Y@c02yLXa6nqBO0|rYCBe5f^&sbZlvJIx~hDJy0;Q8d+&=^^Ht%Fx4 zUZoNB>Z+=kRTcMN5jIzMt%F}rBA3Ui`PQT^2ZbB$!|Io!iYC11aBdvGnK>N+s> zUm96Q;9uRzbUnX*wJCRD6%O^Qq~R69vvIR=eP=0k9J;DhhiM$K+`JHPkX9S@!%Gk- zE9KyuWXK(Icw0qCUwb)IvMu|SSv##nj0jvCY_o4IEa0J(Z3)88P8Xy9s9XCi!5i!e zM0VvLeU5kQ$JX(y!_>CcN;HVmU37NyDO#FXvmUs#jk*pQC))c-^jsoLJI?*iFDyE? zE`s$1E#5TZoCzKU+s)F=y}+9FnM87$#u_GV_dVLrpV7i(&LWE&uh%5@zRr?7*EkB3 zUk^ax)p~%a%u|nR+jVe6T$`uyLB?(huOx{2u%JV%fYFd5k}> z9rH$fV6!9wH%fRZRcx74EIP%z)KfI^h)-VEuaU5?40e@df19m_?R>j#A`|xQ?Wpbs zU3z;^zfLKaqni-?LTeXwLGay0C>^w!MzSR-Ym zt|Npl?`5;+bKY3t3*8YTeCs>&Vb32kY|n_Wf!+16L}3fvmH~EeZ9)dPGD!uZ*r_ml zUIpTdQyCJ~yuyYGl%8``xtO2xYR1n>l``!T)54?)5#O&0d&wzdk2@`s)UAuV^nZ)1 z@l2ZTQE?s6TddJ%h zDR9>TU5gu12EE~H#7^YN-9OVv!xrPPrj<6-0<=$)&ysP%^Z^|a6Qj`${LGB&)!p}U zf$@+SDZLxd2oGeTb-7HQnAGfm?iE>qMfmD~b?;_l)cR>+<`}qET z6jE=u9lezdx_tpdN}D~0LHH#way*~I3_&(j`eAAopPeck50S=!EtH_nMrOEw)uI_c z?Uua|ev>QJJ?LyPn_efUgb}w=O>VbeLrXE?*L9=7EPW=nrvOXnu8g@GV{xCz`;-2< zG9oE!&!29};|}T9CSg-(&K`P3P5F)9a6>89raHX0$;L&7y;APikqWcJ%-%r?MO9pY zc)RA%K#fgX!Z##Mw}Ix6sOA+85wxvu5iD{EwO99~5FO?4b^_Z8|J86bHq7yQUcBxQ zFHy}aybxZkD}%iRz@2!77m2y;-)=fW?&}&Xj&iYnF{{C8m^6bgi0OCe(}qMfuaH@^ zS>b(7e(k$gg{c2;Ki^TQh{Bk{hec;8VI-cZHmtWR3pZ^`Q(VJND3 zg&%~iEiuAWdDD53I{YrS`c6fG@w@5`+0P6XA8Q{Sr#St`XLs|NOEa0# z*yMxc*;y4{KpS*ZoVpMBTHd&k*bf(x;@z6zJk19Ud=+Ovu-+kv)FRA8di*ZQw)ePP^tB9l&A!!hcroARHsIr}xs&jtAR#wnqgUn6 zeliQk`*-v%9kL()%Sc}hk-tsji)GaIrkKGBf&4fCnZ*jOewKdi+(Rm__^T}Epsl8G z6igDV_YS|OlsxY^{FzVVyQEd&CNKK*vhDr9TsWBiN#hlAVq zm7*~Hu1i|`OGQgPOud|Qshd&}fY+a%UFQ%$QiI($eFiT|7p$N%L$ZQA< z>}7DOjw%@E=;H|2Ot&+DjH#@1m{Xt3M99RJP?l*aORJ|OW_%wo% z*rgADNisfp`?-FL;hXjv)HfC9mhdgTR*wMhI$}p!rTS+4Ci$YyI3VKc(HyXc#(4`z zGl!#zq2_5VI=@>dVa(yea4N;cGY2&4RLMq%kO8GB>}KRCQaCk)|e5grubG6;=rDMm7I`a4mo58*W=s(FQ%Th|?a zgdaOE@0Uw1%}IXvN5b2+mHAwh!@ogZ5@%SmCUNfUSg$Q*@s)|!-2TSLz*$9QQ9F(z z+?vh^j>BpyMK)cN8y{8tQpCI`Po`jl@NM!C%lWj;r+Ckj;#I1fnk2IjJ*?K?YN8N5 zkQBpJYN01O42)tRHQLlpYu2P%&j-UJHre9|W31~lf`PmcA`Ga0vU@j`E($K5w> z+UDDO_p+DaYRS(ra6n~ma9k;^+J8_+H>oMAd6@+H#|>{9>p)do!Q-YIYOiR4eb5!w>*QIm_?r?0yBn!i|cy@S_5zzeYq_CGtH8y z<`pg@H^}I*lF?7WBD?}ZqdynxUyAibT%igE$myg(U;9hB~~UM z$HmWQ`LUwJJA`Kc#Npe#J!oRF)Zo}x3f;ez;^&AuB&vDo7Q?3}GymYnoaoWtA)E0hGZ|(l1_V7!%iq=xN z>|7kwQsnVvJVJ)=ft>-I*;$DLM;F0y1#HCU2?EW2bcMDFO=?@&eSK}5q= zr#IYkJaU)yf^mS>(Yk88G6x>Qf3AQLAasi-jE1aGhRG3QnKwNYB~DpSyzvq)A)! zD9jzE(US-Tx{PGU4}S+ee48#jo-1fGUFgSh2%bwL zH*XBJ$fYTE#IxAgA=kcFQY_bhifUfj8c#g$Yv{ST2z2SEKqXy2NY)W_PVfZEa06wk z9w#99z%xWD1~omSuMjDAJ}u|U;CKRMb3l#lb9s7Kd17Y2G9;>bh1XN+@JfnTeMaf4 z9yeuOM2(vrJ7&{GJ%D76JV_YSJSuOR@6w-)AG1z1v1MW~u@q_}b25Ka@%S>?A7P|C zDg+IFVmXvz=(p54OI!4(hT8RP>7!F|0@vwJ<{-9oblIG`QF2iTrPg56T6#g;*fQ;j zxkcrQ?W1b(eogF6drIb#l<&<6ag*c4#20&m!wDomd=vca8|$1QlND~eCTac&Zn2EI zIi;Hwf3oJ3WCY%o_aZb;>9DcNx_>sQR0t~;3ZY^~uYy%L$~iYFr#Z+Iw4D-~IiP8M zOeMO7^t9E*4_o0R<2Dzi>8ec3FL}2rPhlH$&C`9Anj1Aw=X`_cYj`H}bW}~qOsFfL z?wL3nULQ?)4eZBjZpJNaCjplY+saK1zc^FRQkMG80GEH?Mei;7A;nAScwtoiBUww|GL&i-Sd(?MT-Kh;xkGm!HXb$oUZTEy` z4rqLH6i1`-L?-q~!kELwdw)VRhokM8(9GdzdnGh;KvTQfiQn5)mxVASpUefBa<1VA zHsYc5>vQSXgddldew_lLcC00jR(U|%ke4OdcPFsBa&I^J5CdDQ2B189Z8`L7ssrYP z#j{&h0EEqc*mNgSp~roCzoGOJ8NUObPR1uI$Oswl^bUdRotEw-{CmPR_%^w1WBFb^ z?vM8-@nopdOK{g8i`vj5*B`rYclsUa@NOoZyGSSbj%>}l`xN{WMx#@7pO5%sl6@NE z&&R*gIQh>n>a)-;92QAp3(==H*wSXj07HKf*okz!t?HOkClnn7kO>$n=9ES zX~{%2uUyH>wz)6vEv_FuOXmd1a?{aw3b|>u+(@Nz*+KbBwh!tqT<%P<3}H~j<*4X# zv|lbqv(p@j+R!7HBQ!7VH;gy!US(NoHgI7=>@*kjADctm*js#iqMv@wTe8Ij?W6Lr z`??Nk6(XrEO!022gws_T-Jef{BDS8og%ixbFq`QYs*Zq+Bju(gY+P` zj>deE^b*atjrqGN9f2aM(^0$AypjIg+*jN)X16_!nvU@cjVl4GdOG8d`u@0LLd0+; zs2?CgG2BWyaC+gI7Ci0W<`KZ=%gjN#^oxq5ITdkZ??m`MVkgU2_Wj%0a;P3fL83D? z_U{!`1m5}wgS&a|im9+QWI-hINHZ@8%sZap;!=Vp1= zeAT8+Y3GARgXF_mMGdzk5(Z6pMy&`=T=vUdhFO!Y5_G_a)nsZ^f#a)`d%b^AAG;{_ zr~)0BE6^Tzp+{UG*1ZKvoJOyAxgTyz;P6I7Vsz%pmN~79X;ScGDt{r|nea^h z>Tq}voj^`A`$&P=+P>d~Q#Kn1<#P3YzY-x4h*gaao=(lV=WMv~u;kCES#a`|Piq+x04QwKVuvIS{8K)mV+ zrau?ztRHBejI{)|3a0Xe?tG$j=kHLO@D?>E;<>cl-aqBF5bj2a-7J!;#poE4FIeI1 zc(sso@fyDQxlKgs349CXHmTEAnJ+h6pbDRNqh|}M-reI>`!<@DF|qQLY+vz%!XY}I z8TJ7!Mf=eSI4g~-sDw6VtG`PbOxU`6dHWu3rSM*KSu@1r%GB-ML&S%S4~stWUZ<;# znP$|cZ^|ws2Go&xuB0VRiy&0`&mc(kBsUbXW`mI-MKF_*F1R@t^eix&oONcBF`CKj zc+faBCpyPVbk<`sdPr3Bvil3Dhm%zgMb*Qtst5FC7p+G$x5cU|wK zS{}ks1eds-NEY-Re^|0`ij#%RysMd1t~2pTUS*YmY%DZ!Q1_y>IMeI4^vx1;xF4BU zz41Ow?(^>-$-n>9w@u7gGA2U!QA*R8pTpn;VW8E%AyLiCZib*=E_%Dc{}JVNkpsKV zBrM}TJzb^Hn^c^IjN1g0^Rkr4{He{EhnK7Of~T+fC&c%(m@hN9@YOT!pkg39K9EeW z7a9w4xjs?3{yx<+B&vCZx03@>Jzc5ZL8XTCt+Q2{+P^H*A7)Ad(56ujA$fSzWKR|^ z7(+$3GQ5(#=ZaeaZnEITJsCECS@I@Lb>G*2`R**G9f8zN4&O{~xFe8!i}{$@p-RrK z&5AE6wHna78iBsK3kdc}^1z<4%Y~$E^)xxH^f?0>_Cf=qK(n0Pz-1_)ER!`3%fWGy z;4ncJ)x1oQB_9s+yxl;_mb=JB{Zia64$rYWIb|nmLyzntm!vHm<=ULPQO3;?$xJhS zMq`pmE`oMyn*C9E^OGo6AIz>sbxL+9()x6v!?_I=f9GMHbP$7SyDi_tf z!n+-NE8`o(y^lbd6=n1( zYI>H5z4&22760&lLN}e&eW|BrTF8*$kGb<`q5!TH(VEGIYsgj>?WkHGN|x z7g~q^3|LN07ne`wKAB{38L^MuQw-~Pp;^*Nev|%Fd#4_Uhrf6T5kPG!LqG-i3N4#O zw)Ct>dXB}lPg&rhUoV)Q5;hX+tOf#S7!*_*TB9;*||=YAL@cf@%uiGi0S?a!xaE0U`tjRPi=)EDrR>14&$iY^22a}-EC zcTb4S^f{{fmXcSV;CWv(p4GGH{@Y5$I!i-E->uPRQ(*B|r8C`xTdFBsd`E+3w|iD^ zaRqNL_v^S+Qvgj;lnag&eaDqMJfF;Uw1zC#&1xKz6O^l_3(lL?4 z@9GO9M0)+jzd(wZ5S0&`EicqJ*7?N8D4a}Jyk6??33yejrV|wEEZ`OW#dQ~5A5<3V zL@Py~hkf*W@?v57G>VG-Y=R{7^8b%VotIljGL_E5jz4!>A7hqaYg2)cXu zubIlu9eDl&c^dz~^H@i&wFWrWS!&0{y0^}vb;|T=+kmLfUCeR_CjEi$Nm8E#JN9$D zO&0Wp_#?j@4*!#WiuFJ1CuwIb-lc?pO7*tN27>-70dE|elkBS{3f2XRYF;MU6=pDP zT40o9SBkEODu(+?;9R@rVk;+pE?;WfYSxm`L?9(&*OS+;NG|HJT(EXi3|i_eR@fO_ z)*tw7sk8W?QU7^F=eyTP+KaUo2p5R(7hniKf&4-k65+2RJn9G+itvsIpM=mjE?44f zRN}wkH6*Heg`aZGAnlX267aP0c@caBJ*yeY(0rGni^bgr6rUzy_?X3ZvR~vzCC__? zxMpXL>ze76OW}n?O#A%6n@gCl5+si%Kk(k_h>Ee?v2IK8zLvT|?9z2|V-2fF?W zW=yw#4V>)6GCQggMl?WMe8Lj<@wpnm7B45`qMDcc%v)FKFbr%Q{B_D%2tPx8x`EJZ zuG@2U;uL=e(xn0^2JacwP=@m>Wa=C6sa|5T!^v`%Mo>o|hbxBlKg*Au!g1T8IbmN6 zFNd2!(>NiQ?dz0nQ>R5WFQ-m_4iN#9ejJx9;0te09@3w2gb zm_)S$XX-t4_05Nsp0?G7w+T%~O9@s5n=^YsvbA`rlSwya^f{CH6w?-)r~jtH6_A;a zD3||H0lq}uD#d|~;21Q}ywd5q8x_Qc2%?&o^&J)2%x(Tqt1C5GM>jkr$Kocjcvo16 zYF^=&NiWpLQ)N(pb~wM^Qu!~l@{d&FSq3w*!}PnMDnap0!6e;B7Wb+kDE5pnc|zF%t%RFvBm5}#Ww{q zz^&K`!}$Fy8v>R~8?G!>D3P5e3m=4a;Ffd0IC_D`WHp|nIp9z?N0a9F9_31Tn(Q$S z_P(b)HO|OY>!%1%eSuVmL^ZGQ854mI5X$}nEc!1FRFQkUzG@* zl?(J41!`9yQOzs-ngR{x0zIxk9SS6>d44Zng7(P$ze2P%+4 zO~jdvRj8{$?J5>q&1fVy^s%JGR*IniasskpPnFUY*v&?4HQPXMr6Oi7NJWb zOlqoy2gsO0lkn{4-DWg5Z4Z&DDJ;98soqB*H?JYpRFr#Dibew6SjFOCU~70kWVcIi zV6((@e$z(1Ubn8*I$@{1++Hi+d&+y|7Pqc7jXeij!S4H#)k4IMx1h3uoOx}2#D=?| zhZ{I4RrfM&%(B(A6?l5ioG${QIX(S#ba?BWL=fb~uDl9AMz%~|T5Z1eW#eBAZ-@MU zNg&}raiZg|_R>dsKY(BLBi8@>bylX)dFm`e%e2h%`eC@G?q5fYgPQ!UG~uJlmD4?n zwx;ky@mUu0dBO4dreknL#y}o92Bh!W=R~iH`$rBtw%Y~$U_j6}NS4MNv2%|5Jxbvm zw6S(;a7`BcMmNE-Y55EpKCX<$RSH+K-(yj;ze$}VrC0q544A?a;D z&gE?#-V>ISQkJ=WZ@n((cKa%uhumeSO*xL|aJTR}=D2iJA5trSA{?(Y9E)|9ZCOvG z4z3b}I>%}~58@Ex)@pM&uPDxY2s|2Vv^otf=w8$vc?6$H>?qAa(=;+n+&psNt+PRr z2N=QoRel)1-4xd*Ye3n4eC^qvLYNgU%w2JqA1O?s{u2x8>eSsY|5L*GQ)k>jl<pHcpJ8sk)^72PGg!b9@L_}zPr{58%c_+(9CSNdl_8@!a9F8@1N+w5s{Cy7>Bt|7-m3Tojg zr1G?8<2)$ZzcplzL&7J?#o)7=LKPum9$SFM^moUhzwf}Y!!I0%e#bcUm&c)Z95gon z+2hcU9EZMa9Qvomp}#o}z4PF)^RwqT^sC3AKQ#{hpX1P{9Wr*hyNpABU>y2OXqap>odL%(Mn`uE16Z!~}GbPpbfe&aawm&T!YE*P8tf^q2gjYEHD9Qt;L zjm`hWap-rAL;w9a^oPdH+1KHH2#KWiNNr^cbL7>7RL$g$JiWgPlL zKSnbPpd%mu;9LP7n$yn!utYx2NNH=GK`cRRkkule`a;L z98DoAqs5bnGARhB>J2-I&Wy4)@cE^h5@!5ZM&FxM4yU1|Yn;~_?T4#h3T0>6wu5O< z+1ctx7or^5@(qDT3^O&@Cz&-#X7*L?^iHs{n}PeZ*lMwM_fi6ti=pga$l|Nrjqh%Qvj2R>nKhdIM-#? zpF2xV96;h@2@;7ov{G-aJthu`<=M*QuD0sO3E0)%*;MN z6g%5%`f;){6K|JtxhBwKPm`MRQZ^wJo#b@H8SZf6BO4NB?NKQ9e+_4`WM>e`=Kad% zlVH$RYSeQGt}6tmAwNT+npgN7Qr+2RC(=9HR|XF#>ROUyOxuQE$FtGMaad0r))og* z%`5zd+QmedkvQj_9i0#aZgdd>y<#`A*R@(qv1y3T)kY1xW>|5oMml0Xqo-M%+3tZy zS8}PK$$PWq?iipTH{G&v#x}^!xoCl@yKD6%Lg(r>@#1)vT^lO9HiSHF0G0#yzMG`k zeAKX4cE0tu69S~M^Ktwlfu6>VI6byrco>rRSmSpM51Qzcpb>CjL)9oF$d$`qYdl?{`UfE4q+gMEd z7IugBOL!F>uR_q`SSepcW5p`Y86?wgtjh5Y8nw@s$@BWevb4I-RQmp;N+jiRFW-jD ze)vh^#kaov|BRhAzMf9Glo!U+GvrjBcj5h4!pb50@<^!nPd7=#cOEgp;Vv1+u02`e zp6~cla<|^VKEyMX)0wUa+^If&v*cxEvJjZ@v@w3aHheVS?p>HGq0mk!+x%&JB5lvg z4v<-HPxAZgk@@{gO7Pu4-;MW~z>3zT%x0xR7`Xa(dl!C_@f%hC_eSt5OsTF1pX&NN zm_*RbK|B{%FxyUVidXm;9e@Gqho8Y2-_*4Mn1m7NFwO9|$oe|P*$g61vEY&At zEx%icdSOG;jYDZExUgJvR1P#n9T;R5dU9{4J42=Unu7@S2lBaQx?gL@J(4|IJ%iQM zJ!NqJ)ID|Z!qhz^ShA{_J|&t(E`|iQ)rV}B#MjapE`sB2(u>bR*tTmEqd}(T&Rl(h zosTZqOWY%|=I0d#kH=(8OpsRRjtZ>~D*1yrb}ndeBN)ZDpbGU%lo29WpVPRQw}C+M z-$zvK_0(S3^&$Mx^0X~f1SZ;qGK{%RHlE)sc^#9Jxm*|jPfhV>|IhJN2b!k;v*H)R ztt|t^@S76Iq%Es`=+CdIG&v~DFnPEoajZ}}!d~gsgrAPprqnHrx}}~Dhc&~k?B%e* zU4SawninTCL&8Uxl)O2l_ZQ`9F{>WBwN{!a*4)&XZC-dojw%Jw0>sr($CyGdD?JM5 zb3<3xW(i(pZ!cK=72efPs(l$Z&NDh*B}<~tPRZg5CFw`okiAz&&(G78Kc%Lq8EmCv z^X={4lnp#ZBh7YigUypPi{5(B-cfm~+rp1LzmK1>t2nLW_AVEn^D_IBO1J}%l9ab? z!H*7rP-RU|Y0vS)Bk?NOlQTbad_&9KR!6_Yw@x47#$}-EWVlz~Kcjs(M|;j6e7zts zXRXxX+YvgqGWLI2y?fu8y9>;Q^E zF}#2%>|xU^dP~Xnjq^++|1s*EP?qE?_ zp$UDK3X0)w_NwLc*SfV|xuRG*?_Z7US9 z=GLcmUv|S(!iUKg`_|*Us15&9_3IXP(CNPqh+|i~_W$SesHq^$Ol%lFktD(!~ zTBC?d2NwogO2*%euY@beRh4Zxm7%K$ zk?pXR&?Gx-B_7T_#bn31tMm_*p{t1{`Azy2z75`ggqfYOKG39Fe$O;@&MLIqB`#CY zNyi!UaBBEDR4W~jZ%4@K{nTIM*wsBVJkq$1OyIL& z&-~T>tB;+*s+M>3YuEehoIr?{o&_7OUg+NJCl=mE7n|ToeR)^7gly8#2GYZfrKL|_ zupL;2M>|s57bIcMn86yEw``3G-h>U8KT5*kFX<_Ulm&Q~t<9_y?+6oY^g~>`;+?r> z#5c)(*SVbxp~GYPW~OjP+bgvlcsM;&y8RyH?>+IDVw>~PT&HiwWv#LL+8wdaNY{2= z!WNh6;p({dM^kCDluBmUy1neQy>L#BZ-=)pd=c+BZ`n1QFgKmp6i*am%ewRCxGiay za^4gC!t}MLP78O0wVk?l^|mP6mlNGd{-S`4MP(kn-p+&HMC`*8fV4W-awIuf+xsrq zOi+HD4*zQcx#7~}%4F_DwZgNtfBNj(%634ZqgA(hn!Nsi&SB6ZpjK6u;L#0+4Abm# zr`Fshp=`b9j?lcPyD8Le5Y-fsQ&EiTJI!1fQ{RvGqY_zsM^)O8EtZTwxNjZB0w;?bx9eEu=?c?6KRU*Vz160DwfX-<(Zimv@ zGO1*N`e__qXQ``Ya#y)DsWse%#QQggRu4)6x5Y|qWk4NId}>WSMaiWs6kT2#A0_>+vI}Cn1FasB={8V_2Z8z+lj)PG z+kp9%mg;M;j@z>O0zTh-7pUVL%qs=+hVY0xo9VN|L&=#tukzkV&lx#Sw*EK8%w%|0 zdR1)W9{nn=_Q+IMF*5PWnULW_h?`yUPZ5X-is+A2pIH^`i^q z)c4tsw^h|4R9RJL)ElpdTM#J(`5=x-l`evSjOg5Vq{Wkz6;y}JNa%LmfpsA`4gJSt z*nQ6FDg4AN%NiuLB-!h+hBt%^6ti|-r$=<{y!t0blWhA^>mWsry-(CW4&|$0e(mK_ z^jE@^d!oPThtscozH%FsE=}yI<@x_ zXT^;tUy_U`KCXvi3YxLql+x{Sc}QW&f%g$L5nTaVCL0-}a$z_DR+K_P#!Ltb9tVNa`J2N6VGXcf2zgYYt&S6!o z^C}OXpGJzg)KfxSijA`@T$*M+=iPd+?QMjk&R)C1VUrr`0_j|Dio24eT#nxyKUN9h7NshOdOl?x}&|AhiR}~#e{_hK;d!pQEtJl5S~R3)fKGJkZWe4 zvp8=uFRSrV?wL=A&Ro_-1%Dp1RMv+`@$$~~Hn`R6n1MQ|GjiW#qpu;dT%e-zTL8EIN^2anBhl94W$4BD|uoukx5zJiw;jFo>w^_E8L$Q84c^pqhn`TPq{c6@)f! z42Hzdtxn7=_Z}AP-m=xK z{;E$9rmf`HIey0)^J|o-U#C$E=_2xznsd_G4Uo7^6TqC_NWPno6LNL<6zmS*WVh&f zh*d9_>+rMs1mFF}T@91LwC{LY(|xkzUb9N*g6lx#43AGrhrvqgD+>0U7XDo#s;E7^ zjk~PN5KHhlK{2#)1t050CPXKSq_whA+~4p;HO^h({mF-1Kg zwnyR|yV7n0gK@JKr>A%r%XRTkPTtRZFB%1t_?f=Y;av->Nu-~Em4FxHYJ09-qH17F z2rLDnMXafWbsSR`9p2l$h>AA&Al3xn5+3t0LnA0$ZsHD}&k(xcBKf(mR#qi$7bPD# zVB&v%cE+&F8-&oMJeurcHW86nu*l{X79H07;{>~4;yp6Rd?)V(Q_oXRsFM7GJr|HS z%fk$k3>KuaUDleUH<>)JH{z*SZvS9%t1GBYtIE|EXUH^PSB`c8>{Oh;k`w3Gk#?;y zSg%Kiz*kOREh^o9oP12%e3JK7{MN9t+gHn^A(s-LkdmbmVK}DJF}bT)eVSxg(LaWW zoh_}=$JoNb^o0$SoKfxBP}IVjx?~2^CT1)LMu0&Ej7hAxBJd&_^S^{ zY*6YZn=x)OC{>=mrA#uRM0<7~g7&e(`vRo$h z-!4tDg57{vM#E;jW+*& zsra?;kn)o=|GrHAdc^#0YknWn^i&2|TWRn<1<=DHlm;KudzwIL@C$nXK~jLy;8*qj zd=~yKoK7ni;H4qWZDk3dlN-YCBoWF6)}Uar1j`1-;JewoA+Bu4{#K&gyCEi6Vt+$G zu(oaP?nvfL1HaU}0e#q16gA*pa>uNr86^&O}hvpII3k=`4}ZwCr}l9$S00 z3w;ej)5PiM1_?wEp&AF#&Ak@I1u4ZrWc!TiMZ+M+pG{Ae>o{_2CxcH_fs5SgBA1O6 z2dQ*cx-E(eQi+4a{D-7q*x;*rw(`%eqQNc-Y&Y`_?wPn`WvqhN0|{ZY*UwU~H5SG3 zlUU~`guzD>SK_tWsYzPfC9cG4VL})j={2N5WTK-5*1xVv{}4~>N*kh|{Q)u;p_eew zRL`nqgc@HNM{U0N7E^x2>qoricu7-R z3trV{?VDq!4H%-fkRqR#=k$3glcNwLM7AHu>6``Io3ys#eLar%XFfK5$RQ`4Z2rcW z@uqFw?Q!_ZTSxJpkKpAN_jp&MAJy>EipZ>JDK5s$4^VE5N!Im7dsy7V!iidf z?Nf63=?uc_z*O5Y`*j=miSDx6bm(ds1;FYffqL zRG*A$eP+Mmv&*g#cc ze9}#`%)?h+ZN=!L_+I?EPwAcm7gqblQtGLv7=maofO-hA#Zj zkL5f13{&8tPoCI&voiRW8ptp?kCyQ$S>vaQ<8h(0Q?su4y%_Vu3kcT|ktA-?*PXFInQaHHkPRs(BfU zc5FF+JQwbxX*f~M%ffX`DwM;kNVscV$;}*z|fm@T?I%eyZ!<)zfM-tUrOFqH!d&07+ui4o=GWjZdyTez1{(zZ<=jT(F*nqZ&vZ_lWCew7jZ+E+Ncqx25QTqJd;i@=@(5eQc^N*8Bs4~EZ7 z;dg|6f(NfhSxD|?ve3iK+Dvnk-NE1kd0+7uW-cW4t!5ZKT9UCXLL6N8z_bMn3vKBEVt3UIP-HcPG1S(Ipgz>9(rD7#>NL9d|z-_ zj%RcqQRb%}8OP{j=8?>+WO&^V9lSoSq->9d2*S%K30@oL@cLdJ5rrOR<|9Sq^}Mfm z3^ON@`mPGEUc-yogcPp_VBy!4OkmIGL7Wb+hs;Z91eV+AVVtA!nkBr7XZ~nm3QNW_ zdW0w$UKz*e6Xr1*uScPS*C&;f;U$9bGD?EiCONz&oR-RnUsLE|W)o6GcFFsS$1vml z)OS^Q%{IIkd8c@N3KlLI42a>5KF!17^_Y1njlgmneFo=fyfzhHr!PHYd5TxYGkTmT z8D1I3=(FZA8n4em2d~d7DZ@(y;boKrug!9JHMK{D9%cleB64URFYy>ge@}f^g%`^O zv`4h`6t6G9!mlZrz@E_;aXP%dWL`=mu-ryp#yJ`crh|a z@p>8-eoe^)_Kcpv>G1lhc`1#+avOaO=V-jP7GCG9@#kGqyfU8AvqZ`8$~Z>Pna60n zz78F{zM-THFA;>7Q4+ki$>H@#9ub8eM(a)yX~Ii9hSB{}-&NtYt>J}sm*Vw2Ec}|1 z!MFv_=mj1QuWy={(g-ZK(YJ7p#_N5;>!!kE8>Dz;JfjzhlHrwcjJ|Ciqw#tPI(RKt zQihiZ!pkTLUYycMzmL!6@lxnvw9pihALo6=V;KD}^<5QS{e~BsS&G+pVBy!4OkmIG zyEq+Q-!m_z5m;`c@8cYe7qhXQGY;ACCtpeN%6LXE6D7kd;~4$GJVxX7L+If3BPC^c zi6Fd;lHj#n4zIuD5mD%2w6zqG38&}22I4V{E|U7L3a{-AFSLpjuOGw0uPK?pp3zTm zI=o&nFQpM!ZlhOmj>c;T;kEweL$9ZJWjv!5M9J{VI7UA;kI{Jj3_5tdrlbrn5rmgf z61?W*@S2uKM4^Y#a8g8$%=?PRFuF+UyDGePG`!F%QoLS=gS01DB+Ff}4 zX2}m9O!3NiM(+?M!z<$${mnc^boku_BOoGDpI^Az{0O7nZTZr55eJ8FfXMMSZ<>t&e3@7BfM^U@cC;}yfU6q3sEw> zGLBJT9;5LpK?kq0k}~-cL3kM@!E4_fUdQJVQRrbboD`7@^SdTE$7rH?jK*s< z=-{=wk}|wR5MD+}@H!xeS5tdb=wURR6p=gfc!|d_x=8A~D!k?yUT765UY)S;Yf2`t zXEX_?!>h}@lty5=jV9w9jn@Z+*LJO6dO5`_;~A|%lnk$oW7KUPqw(s24qj7~l;I_U z@G?q**MZ~VrO?A@I4L4eDWO$)fqrn8#?mrb7p>8A{6V51yiJfjVXlHrwcjAok0XuLLp4ql;>GQ30(UPejqT9Cu*?K~n1J&cBvBGMY= zz6Rnkj4qP;t_rWi3@@~b6t9h8;n$Q*V9%%*r^9QOc`1#+avN=eb2MIu3$L|i-nm|i zSH?4%O_U6;jAOK^d5p$uGw9&8xso!xL=av^N$@%%hgZ{lp+XO%;iQPHpT|o)hS5b* z-&Nstq~V2Dk>a%lEVwM5XJF50OPmg`t;|bl1eV)qYn-F;I!bt5*!Qh$ej?);Z9|j{ zuZ&}~t$B>b>wVC{t4~Q8ULpuDqa=78Jsw^PJ&cBvBGNQpC?3P;BB}4H@H)ouLaRve z;%q8-DVe~Y5etejUfY?M(g-ZK(e^k;<8`d?TJq19AE)w_@r-sLN`_a)F`8o@qw(4i zI(W@hQihiZ!pkTLUdQF|IxsIm3O$U5lOl3K-d8+^(M3|bokuPBOgEDpI`mgoR&IGJ!p#y>L3b z_BJo25m;`ceQ=J(>tx~e`L!ySqBB}4H@LFhip;e@K&4UHEl;I_U@G?q**Qq(Yn)-W% z9!A4S5ov0V;xUXalKQR+uhR@Kw2Bn31+egIN+z&pbQn&D*Wu=+Gy=F_$@xs6W1IU27sh1bvi@}Uft zjAwKrQ8JH=V|0>vjK=F^=-_pVk}|wR5MD+}@H#7p*ZFxw6nYp9Cq?Aiysvl+ql=`z ztHNv0@ItFd@mdHAzoujYdq#_JI=oIbFQpM!ZX*uqkAYWJc)j?q7nY^+mGO*DCrXA_ z#xXj>JVxUcK?kohm6YKng77j*g4fwOygrpjM4^Y#a8g9Rp7#}xVRVtycU5>THoVX( zQoPQBgg&kSLk6hoD`9svvR$gcnqV9q`s@dt7dqiRit=b2n)ZaWCDB23SErX z#pb0n0?Tc53C_`YEfro5UiiV6QoJ&r(Fci=;gxZWK4c!F@wyZ`czsw&8D1g?FQX)Q z)pK|?t=B5_Fd9yZ$ToSr#A6s;B=ubtUJb(wts=$iGFbREB@@^)x*VsIuaB6Q(g-ZK z(J;=@cwHd8CbV7lREk%|Gg?NJ46lr1bcK10#_LMx;B}RfGQ30(UPejq8p`2ya2^qb z9!A4S5m}h`6^~(bk<@opcwK0Cp;e@KT@4Grrep$pM%UnUcwK8=N+Yn`M%UpSjn_rO zYvHvYJ2}NG;~8B~lnk$oV|0UgjK=Fm=-_pek}|wR5MD+}@VYpM*R^>>6nYp9Cq?9* zysvl+ql=`ztHSFN!wan<#p`BR_%$UH*fY8Xr^D-3^HLgtHitoG*L3vdv0=?6M+EA-a>NU%QK^JDWP7&DDPG?$k4}uwP&g zYCa%``Lu`a4M)qfi_hqpMFiuVXBVHTv3s1h&BwC(bN2Oh&-u=lOLp2t7$pfJcK-%` z?H%?Q#@XBe|JaW`zCm*?vv6kj$?gAcvoqIXI|k2#*zM-bJXj(*&bbVWPljdDlSPUT zNw&Ukdky_MS7zxJhJR_BA&QN5tiG%rg>=-F=nv_h%ZsoDgu$5r^FQxVBKFij%NF?R zRX#V?uY>>;oX;tG+B|$I{JSx7=hx(;%iu1;OoZFJc^FF_5V7%3ZJGV3E8!}eWUaOj z^25Y+@$3S)=xJ@~b4DDZXK=GwI$TDKcxUu)NAHYw2`E4A>{q8ZgDW$5C4Uu9XP+-4 z4bIg4fMRlARQ*2`9kavSe8t9k;Hq#w^xt|Z)#PROKMbyoS*LIjp5dA8pwQi(9RDyE#K7Q+7k;r}+Dd18npcqDMIStR@-Q&=ivUhii%+eGEo+ zl?esWT|_m)T&{Zik?M_;lQ3&@7ZbJj$?gT$&>-y{rB?F_uOh{n?rNIZzc7%R?xiuK zY#iZcyZHU2gvEg5_76_$ITLLwDLcaOV-?RCVRLv+_GYH{oH)B{A5on}70!ooX!hf< z8`~^bTpuMbvAaf@3keS9pcuLJTn^<^L-F`>x^Pui@`B&vBuFb(S1CoB3r7LN_PO$=&t2^w8SB*)Ob-z>@eBo8w}=b$)?SI22eGbbGe zcKt$43H7d7-4}qCs2NHQjkd%!1)947lR;P)g1WoI^?TGo1wtV@hHFR)I;9=hRl2H! zB+PyVYeRmmoseb6i@VmK!@9LJ4KR4f1h5-l_dVd7?=U>a`Bfh#Kv<$GSbnll>fr%W z*ywP@)gxqi8i8V2UK3{~%X&*?`Oa9Dr$emkfn3v@73*ust$K>{f3uV8jXi9)de>Na z#R$39_HoIzj1YZ?|M&4}yPAJ&8zB95A+*=Wjm(mDOS>lC(fafVlfxMls2};J#idlU zFxEH{NnSHjAx$7G3YD1WedRcB4l{tK+2a@xJAjpN}KZI>kkumEBHhwx2vHdcPNFX>vy9SAx2b6&$ekfXS8 zQgZyk)=#atJ^To%`E&SI`Vl$?$14~>@fhbDTt{!pzj>r1d5TAQK5EJtjuKXq-q zQE)bbCy_Ne8f)b163z?-Gvr9x__ZV2_y&ZD+xYr8vo@}`w2eO;w{g;9<&y_(e5TwR z%AITD_qjIS<}D*1*I64EBicBv*V=f*Zy%oywPj1ACLZo)M#1PW-H7*aHM+Nfy%a3` z5G8fiz%Id+*;2|P#&*HN58^N58bN(Mc+j4efVF2iQX3WY@$w&84@S%C!7`Vt2O*_1 z;;yf}eguxQ@Qrco#hKx#w-m?E#5lr)6;U4GI9u*b?}((7qkVeQ1Fo}^0(1Ltzq4olw@ zvAb=Bokk2l&C9DL0FVxd3g)d?;mL>ZTTMLEy3*Zi>RWEiVbZg}q>GP*r~lrVrxJM8 zFomaXh-+E9nP*nl241eNRhzxuk_1-6%uM3N#n92ftWBO%2)Q;R7$6xi+KRY^5Ig&U zKJ^m1L}qRpAv4<&GM1TbaAq>2w^U}Hq8QQ@w})8Q19zX??~^+xGoL3QGPAmO8YtXs z_=piQBS2gD-w}_G@w*z2(ly=?erzPFM3V zG3?!8Wf!B|w|51#{uTcFFv1`iwRHTN80BR20A7&|dG;}WmW+zzWOQG7`ZfJH8Qo8W znx2C<@1Jy21FrKjDr2go^V(b7EUa1N8(VT?*-_k(8xw;1`<22J%TM-gwyekblI$F6 z-{$WEK`J{hsb2Hn=6Bys`ycUak{5lO@62H~&bL_!R62h64?fD_-}Lx9 z52xPFg9V}`ex}~a(Vfiw$uq4JWtQ)c(K1XeBRNckN~YW1GXk>(_{Nyc$C+WKw-mEC zV$6<$Sl0v04ww5dxpSDkBFv=QV&vSr*Dwcl}reKiLI0QcV;yR9Qb#L28O>?a{A^ z;1r8QS&(P=S2d+W6?m$pKvUXZ9OLwSW7#v`(sD2Ck$T66n3 z)U>(1#)~z#roOrztn{DjtCfkgo^_vsx`q34c#hRqvkix6*za~av$R6}_XR40WiQsA zl_y%Lo0DD3+h~`x&0D&eELjERWJ%KE+Nb$gy~OR)s>rp^_2Sx-T<8vpbt&7&$a^7t zgjp&KlgPe%ThKTTZpn1!Z^%;h6L=4aYF^>ntRS?PC&i}DBtKlRM^v*U+)*vim}EMM zTiYQ<+z!F~b8GZ3`wbe$=eWNq?w=HQQOzs-Biy6^#DP!91^%r9e@cNxZRipHNr62Q z#PDU~#9ZLF6!_B$EUI~he^y`&`CDN0?zE7g@G$;0@rvexhpX(vg;hpuyr&7T=c(^Cwwo(2H*Miri_{1u4APq;yC5|O`0Ai zv*Yv>{O;C~=}m1;4?&s0K#p&wN8Ioail; zlVXQ!FM|;4dgSHgT_-1<-WD|MM@&u>89C91K|T4g{C|mm41L)k^o#ty$A6!$A4Fy> zt(y2od#0G)MFc-1nqo5jggM)Y?BwN5@a$gJ#^^MMUj!HALo7``2^tvY9nGOg z(B)SN?g+a$!r3W-*^ZozfA@WPbVPeOm(X#0IR|IfUi6l>mx*zEIS*o8k9>P6;mP-< z&09`BKWXhnk!dfC}Gseb~JJGhWxx|umF zRllgtaxqb842o}!L5@Dx8K>MDs5xVF#=px8E*lM##GAy|_)lr(pX&Vb99fq}%j(h! zma9vlo7Lqs)|-!@l%E2l(AQlc7n2-k+*Jk z3Bls_fxRkiiYWC`{18pvLJ+F5kw`U?*qhwvPM&v@sfX#iALwe!=N8Oiz zH&tzIpR`b*fDHk8qV%%gA_Dw852rcK(0ra3i3OB;d|P*D(YKtTloQ9%V! z1_1%D6!bcS^LV{dnFQqO^*W3H`|f>C&PkdU{J!7k`G2&@$=++Nz4qE`t-bbmQag-J z3eOPf^Re>V^t6q0szyBWT%5k#0zh3~X5!J*7ygRs%Z0kW%tB&>A69*7CiO+eBb$W2 z5V?kUM9>YBh6Z1cc;rs7EZ$y%cqEz}i2wkaL1>{Fe6YkL%#Lq6k!H4?D9F-wtf|>{ zw8Mdr@@DXxti8+yXc6{hA}v|_NA$NUe*Yc6Ti`n2rSzU`A~bIW=-G2&xnjOr_J30T zXqVZ@#DunN7en@2;$(j-fOOf<#iJ>E{(|h;Jv9&5b=lvJ#K>*Q2~3uZvllB?nyU zIh-2it2R+IOTie0%$NnrWceDrOC`_DjLacpEk#{gG&0sxM73p|E~CP=5rfDpAim~} z^wC>;{P>LTPqfbW^#nisvy350KdO7i+RF15+1D_C!@_EszY#P|-4)zgbeEbU$A@M; z^zor+CUgFVvG%q&J-Z9ox}Gh-qp4^771guOV2^HV5fUQ{@nO}o4#*Tf1j}8@c2QR% zTWtJFWMqkX+GY_!Hz`aaLMtMR@g!a+g0|#yWIjHiZv+(Ptz$4xu7>bQ!e+c~v3uf0 zWiNeRSfrV<6QnG%W9?;pIRz~4h?C7O=%6l}-FP%*!(UO^yoeu^&EN4Ic?lnQ-oxig z`Mj6U`}k~(HQ}RQ#&6hWs!|I5c|pjGL?JV3Hsj6_$XJE%LHHK$IEQ_Ta$7`R0VHN$ z{=u&quj2D`Gi<4DlQiQs^EoL@RMDFiG|r%)Bt! zP72Fp64%~lp11=vDa;Zg`w7uf(8FvEHsNr}Uht+f6((yv1&Vy6=S&Jy2$F=PuN^=_ z^WNOT1(sN1g!Dm7R83DJ52&rEwB%bD>6LO~m6?+JOC=eT!&U}|&6p#l7o8P)7l@n{ zvf8r`qUN8)o>|qXP8s&R)6!lw*z-FiFWOu5&*pq=7u@rNyajA9=9{`H1ZdGsYM-=g zkt3?E+qGytY1h$v1nqrbhS>DkkJc#0TPvyD+;=4&P!`5utBf@9Akt*N#5?3UXRr%( zOV-{)*=_pE27DjS$=V0_)IP+Ayl*o6k(v529@{6)_yk|}Pw~-9$Xh^Mpqy@o-Ro^q zGyw#@tbJjV%x20LD08=v=VyW<{B3G#3-ky7#Dn$qQQT0ar(zd#N>6l62!@*D6ZRGb zwzoz{BVU}-FpJ$s0+3cFh>p1&1ohWoS&CVaxEKQ4TbeWy6eB=dm>|$IYrWA9Pp}>E zz1CIjZBTYPrG}&&wqWkimB8Yo$3!2NeG~mqd@NNJ_@ta_u^KF281@)+-{RX=TZh?ivA@2cL^FEwC#yhDGqRa?W z*fFw@DkK=sU*Q>jCz551Eeu-2-o#Y@?CIPO#w_g+paLz?W_TA+_$8$HCtZ#A6`VT+ z@n9Py*GthZWQ)f8m--6b#6RNrOR>`5YtWCi(I%Nq6z-~e6}acx?Bfs@rs5kx47Rj~ zUj|Z&eJbSC2;CZg7<*A0H^(mRlm_S53A~AM0k8G0--{!*reZ~)zIG`E{0g$-GY+GQ z+N&aivbXvR_B$6M?KSF4_*E2_%xi-1QfEZHO8cg(&#fLfGc`jMoje^lN1FVJE;Mt2doUCzdBaqVvMf+MR41Cuy z5@w$x9zX+WUmI!SL8cuy(!_&ElX`6E8vNJ^z@UVa__F^O6Y^2L8-bZC_@ksS4yC5r zzagpUo}kwuBeN65Jz&VyW4M3g(Tw5vD>{a~4uq(Zm<&pd@B`1+^Z8pq30u(H<2(F@ zKWe3Xi8$d6(H9tp-m%zyD5_yHfY zm@2aDKcL3;AMp|S5orc0Hd>|zenLXzXQs~h1)ryzjkF>9Ya01g0t)yr3luM*)KO2T zz(7+2zvDwPBOvTQv6!D(%xPkW`5DA!{x3=mO|tQLYW>!QOlORIyA z_QreZ`V}$;3=_uw3#!ml%n62tWCTlEU4Zwb=|Bi9CX#{#gsyB9F}4t`6Q zLp{L?8E4_{>vR?Hp^*Y3QoeLIlVH%RP)1r2;)BIN5m8_J66I!@{c^wcQ2nBU;o;2p@@ zG;AmjK=l5l5gyI{g}E#7~uz=&*L+;Wyj2=Y@?*xWVTRNqxX1M=q?Fy zFGnksp3+KgYvfitzO7^;JDNh-(TD9h~7vuiFGu6V4Siq{r z4BpdQC#iJ|Gfa}qG+|~^m|v2aHU=|d+$+(N!UDlyW)F&uP9f~Vk7|1Wm!UEEXPHA_ zO{4ur8?4Qjp|bB;+E(9J!dV~VFRL2`5~e(=?=4|m{kd>qLOP%6&y>k$5~or9)`|CU zvjTEn0+mcsdMkAYNLG^+Rmm7-JbRV8H_K<(x8UFG+e90gCJ>Bfpv6`V_d1FJv$C4ckN?iGg(;JM|Y=5aLk|SB!k)dqq;X4Kl-+ z4={kmZw&sSv=nuFmjVuK^Hte~vN>D-9nA-5?=LTzM@rxbY-wEItrdigG07=2|(V z5xE=)Nnw8WbPz^9YwyF5#BfQzRSSz6saj)?!e@xk&gTdlcF5@af>%@{WE^| z#LO9fQ&K&-BP@$Ep)x;d265%v7-=YSNj(V+$`_K0g>VvDU9W`{Q5edOUvf#}G7bSI} z_i^*0@H2v@>1PD57C%FalYYjmh3+SW+Q#|`p7$LDk@6qT*#I|L!`x1)hRGZK4Zl4v z7kO~Vb()HI&-c0j3CS9!ZZHsFvIakqg5&)d1z6(?`UJ)&ABp;Q1|Sa4XAwE2-lOed z(~atj^;s@Z)l0!f#iJ5`A;Oy8=f zx5N+e3S^mSf!10ftHmV!j7(psn4sGqm1$-%x z!k2Kk(iR``H*6TG_I6B7f>5LV5#T!^(F)Js;vkt0Z)e@8i$lQ3Cum30Sm0`qsrOGE z@M!i={1xq=x`QP9rylr@@Wa|CbtHZENjygKsnB&ITlN*NN5NTb=$3I_j&vm@`6*aG zosy39Kn6beI=_w)2f><0I`Io9+4!Y{UyR}}Zy3S*-f*GA3Owukv=3{tKdz(lXLL`Ox73s?7RstG}y&%RAQxqw&L{zsk$=;1{_U;ms zg#{17h_xPgid@OmFh6_JGFLTGiOH53@VnjltAfu zi*F^{7T+r4kIyXf*W*QCnP;2Oa{#T@SdrB=+-9AR_ccGFoTt378 z$jbr>miA}*W+6mV-6GUB>6@i^*?PKfW_#M_pdmXbyUiA7tA*$)BY4*t#K%t^fsev{ zMr{Fe+aq9F$@Y%u7r_YZ`YHek8x{}X4QaiNH1QzPVr`i76r(^0M?LTvJ5MnJhe?p= z?}UL>vVEA~*RZY6<7^AN!;IK(EFMkU;;*P}HI#$$@OUIf_+hoJI>>}=HBk^MDE|~~ zOJvLXFBh?%K_zHjSzYk~8x!<#tO1ZB02Z&FwG7~{Lk46_u&l3v3vFeR2FH~enZQgO zyWp4jlv_0>ir-O^IHQ3C^HvJEg`$TfW`QD^z#0s_BiE2XOHn8Wat{zvXCYr=34-P* z^xF6WnNU+PB9H44fgKHuvRWBsbu`P;D=LDT6fr_<1PMonY7OwC`Wb*5AXWZZY>$<( z*q+=I{)MG|64{;}Ik7}bY;&RYT%n+A+K*^Ri~Ufer2U8-(Q3Lmhz5*}ZD0?RfPjmY zFg-8qAv)hOS)})YCFmWIF}{I*-+(+Z8b}sz@-*kn{}rd-Sl2N0`$jyP`psX^Z_2BA zpf#$?zQc*c$W8dbb1t8A_)LGH$4pHC2wiWWtVY_GLY5?C8QX9`%zFc}g7|=*i*j(x z15k2S!Hp+q71OiCByUofNm8+0%uEW4uP_U@&%okHWD1j83LNOA7}HA%IlA@c_0-VNFKXr-qo91z7aL+zVjPH1$GM+@cq338@z% zM^swZ3sL`Ay|^(coX1Ls^YLlFmFv{K=`jr*p#Lin03HI|4uEJL=KzbDiu>f)c#LBx zhiTkfmxk}JgxpA^7nZ89Ju-%pErt^Hh`#s|03HHf3~a-s87$8}5Ct@v2>*zVKi$MH6PV@VGc52!R{Zb` zq(Q#n2*3LxE@cA3eev696Q0#zBy$w>1A{0{+@3TT-(V2;xL{&>C_W>@@PQkpnSMHD zIKBcS@L{jZkTI^l=ZQPBj)5N5D?38>dUd6M!?Rd=xB{O@?|^jdM8psKy%0vAHKtQj zQ}hh&9Q;b@5NL?6hV`t8SbeRHjCLL{>c!u$GY6$4bDEY4FfA!;{uaa8WcvejV~Chr z&zuX;4oWKS4l?B92=oA}vqXlG#<3lJKmR3b4Nzts@hP^8iq|10YxPAcKh21o?b=1& zZKPcQg{3|^0=TR!W!9}M*r0EGvmDOXf33IuJc_G7`XTHt#3QyricgU|P$bVsLW;dq zszF@4NLt5rS_@2CcL^#B#ivM?v=#|kB?)N3m)|X*7vs|&M9HSSN|M6&ioAR9S%+^U zO$n^Vhkc0vi^`Svc40@dazf{43BXeVe}huR>J#jD8B2LrL`3Es`HjgMrq)vJPB@sP z84nVK8w{c{?3EOL2#Lx1)k(sBIZio=@=OPp6kY)!eVno!k7i%PU(r}fqmYSlklbVZ4d^F@iH!aQa~4Wn{Po74appVM5}!y%pH8!p%;$4*_$!H@gWIj7?)eF};~dljl8eLK*y*EN*4O#y`E@FaYfTZj1-!I0kKrBCyL!~TxrmMbJHD~&syK;J#p(qVJUPG zMm;G{jvBs4`%0H9_U^X0s{w2XQwZXW{qhv;Db9w5pQJGCl{Y?`Xm>=BW`@)Igiiz^0|P|9zL^Ob-7K$Z^XjqD#J1E_(AACiCSV|6&Y1P zFy>X5o%IJ25aN>ZC8_olPBRqZ8A&VvN9*vZdGQe`lF8&pT*#ReW{N!v65U_QI15fc z)t{D%eQ7Nr`iAxP(xo?6^>10FHSU2hE^>e~?scC@28J4SqxKEJe= zKq{g!p+!WnsW133NnHLJDVEUuirmcSmI4qH(tl%(BpNO&C&Fc*#sxpW#L??ok9Fm< zti8QHe)sy8J2Q+4>i{w_VGVlLy}bP)M*dmGc4Q#xvyHvHKU&(LhWMQf)fB%Anx@Ye z3Sz2KgqkGdcabA1s>ko5&av_PSnO?smi8jgST3g?i#u$~>Azm2@=N~(uTe+3uArb_ zg6!Q$OV+SqLavgFEm?t($VT6LuEJ9n{FkgH5vBw=J%`8s*1eo4DC*^UqFI1cO86Gh zN1dH0RP{M>_=fSqY3>1I)yJZhf?ZZen=Y8-nKG`l@E>-ykVjHa*2<7=x=4NZ@m_&W zDEmB$Db_EIfIRjALd%DnwwEw0iTd9W*t{o@k1=|=E5=vkV7nahuw71kzDg2X;`}o3 zUlX~nGk3elHGEBz%oK%tj(>tqi3?kyv~K_`MLQ3irkGc@>b}jGU-~)D|GW(x-T%CW zN7MiCSJeM3)nlRqNQ~^qht<#A&6ubSWcm*H`967KifAzK3X|iAo4EKV6TLbkyKKcNm`hh?=Vy1HBSojm)4BF;Z3Hu6i66?Q{8kD zI-ZMUD`QZsS5i(#F}=Tu1&buB|@+w%*q7qaS7QAV@Kr+|R?NjE7>ib-K6wYW~3 z!PXVoBBgmhhNb{zQsg~Cwuq332$2Of3D;?(B~~U}v`xq?#uQ9jFdlsic{gP%NLXY` z>BQLXXGoBPJA3OGyIzQ`{K&(Lg`*HjGd{<&y$#?*?9lSqQ_0<;qX+g z53+kQsKQP^(&)=UG4AHZc69U;M!ASt&|kxOQ~^eu$~N;b_xBZ2Epy>AK7vdSAw7V7 z5i#-R{mEJcji?WExJH>2o{0pREO(K!tsnnv+ASjCPA2Fn zGmxS`M)24?poryRQGQ$*E#u0lfkN}ZAA)8g60KrMNJEvpO4bk`*TkA$9P3nD5v^m3 zK;z5UG)y_g*ePObk!ISb5S_(7sR=Qg=w$T4h^;~8_# z=@wYf#r^3Ul7lU9PDPuA1Z)5Wrg)V1+H$mO9WTK~e;`DuZlgKaZY;58Xho=}g|NR9d$!%rx6V*P{-8&37UO~Iq-C-@6~ zq6v6!Zd@53MqFB_+P(3gNIxOxb|6d46%g6dpK(ZQ%qf3RXL zB7_zWfe)7cirMjYAks`b5CvK6fHgJcgE=1VTn>MWjj_1w9*^1_HmlKg$mhOZY*HoE zPuzK1#z54_KZyOOBA@$t!#@iu;_(;r@mKTlHxjr_M6$7ZGmHwQ&%55BbW$8t7UllT zdZp>kbH3SeO@n2v_7>G!^!>Er?vLdjdvu9wMVEP>p0j4#XJr>3d;eeaK7Qwcjw81= z*frzXne{TZ9l86W7Z_Y<$W?;LZ3t?9?!l-%4t=l=5F#`W*|hw8iP#`8QQzZ!7U`~I8r zS0DH)x%aU5>iq5ZTN}SqxFz+mU)FBv?p^xazz<%1;nV&));dCjbAKKw^>=l&PBe82h9c6&EXT()G#+vh&EYuk!#N%s2l>P~&` z<3=xEcC6vEx6jZzojXGj$5C-`I0SL zQy%;3#Yeinx9#ZaSL;ph_Oo*C!nFy6(2!kbC(1YYGc< zoZbsR%5>j4TFLqDm{CUtIKg z&hU&+n*C?Sy9?YS-~07C=X0apx@JqSptAGPgPAY9H{h`^Mtr#BqdrA@53Kq1`w!lo zcFZ&Aw~u|@hR(}hzkl0Jp9C`M3_f&Ga@VONQ=fcwM&r+W-&{BQ$pJ}e=bhJZ_ibvU zS1;dEaP6jBHMPNedD|cP%K6qgKmYT_rLTT`McbwOH*Q}0;VUirY?@Tjc(dcG8+JXv z-n--P>YQySw{Cjz!A1wSCO`Pjv%#Lj-v9cU(s!0OYyWATIn6%{T+lGLYVK98`}$5R zYP|OPY2^*yKIg0De>Au^ZG)2f?23Ak!S|l~?{^-pe|y1qwu?{iN%2g%Hs{CJ^WC#< z?%{29B&E<-(&oL>|LXYe9oLtCa^4#wKF`;_*#7g+r*keokf37?AI~4Rgz3FOpD97u`{hPaNyjJM; z^~t&NN@w@n?mas9?Apzpnbosh^}<5Fpr^=fls?WK)5xu5}x zU&&WON|EALd`b}O&4Uyto_vZXehozWRAn?Ey!dabG6wKdfnKB(BcChOijrBK$S5EL zECfgXw}O2n{PB&_r)|LqBRW3 zCOW+#x0>tp`Lv*#<5qnkuUFOls?(>si;9C~Y9Q$M`0^dLwi2=^6cBJZ?qI3g?Nh^< z5x~0CaOa4_);Si&sg?-pd48=(4Hmf7wt#M{x_zM{x8E6r0Xb}!#G>T;-Oixf4`?s| zXosz1Edb!teRIg^RfC!YzAzTp>kb4gr1Z)fRWNg_(HSl2m|}?+hdMl{3Oa5ND&~)o zoa)nj88O1^jJ4DM=UvUUP%Qq_UCrC?=G^|!E9#veg?ryMaNYfjW?tBS@zuwAEcW$U zd;eu)ZA;JpD6q2qH^Wx_ellmxo8Lb9X?6IEyRT^f<(y#JT#XQ5?n2VC0jvWI$PU-o%=PWzK%U1>e$5x zymVnn&&~bj_nh!*-E>n-J3RH$@m^O4c$7{dC7)tIYZQmx!q6R>)Crn$oon6Z~X5THx69&R_~IQFYhS% z4DtS+hPWC4CP>HN#8QxoKMcl{-k22m{2WD@gM1ffDew;ql?o;~6};R@sRNva=VQ2l z-x&TWt1w6YG4i!kOm71JN5EiEru-e<2QK_oa8_K|&{$E@k^cbb&BK&JGGHcQ`C}={ z%mFV$Q3g&GDwUwS81RdLi)$5?C-H}qWlD2wQGXP04L}!Hl`EW@;F{paNWTYvmm_Zy zzQ+N-E&i?mPna`S7NZR8Ay)z@AJ=9mGr_M9_#MH=HQ>Jr>D};$JH(Z~sP8b8l?S*r zDCbr1b0uI`qnx9Fe;c$e#9tqzF9gjWP|oMze=?qvP*wz!9yX8V*pB<7>5);7jcBNO%1SUY(PPAH0=;uLWx}6Pr zd<#wlVwbZ)9ES>+&9ee%7hWxdRvahg0T85Dc?SULi2)J|AQ}4HJ~6^5p%aDBXbo|d zPq_x5JraYSNlr6?nt3MFcp2f=5yf#Pq*(c2CPwKp9K13zWC-PrlTuA8SX-|??%mo z$f4JH{A@_nZpg2JMDNRjHtD6Xw2||Y9dFP z^cl3J5)dl~xEc#?EzJYKG7(p0W(!|a7^fko^x{Q;d$pB;29oRpW0h+l2(mte3Brjb zuFo38S-oo~L$~6EV@*upGZ5%f8-c`Vmm$XMUmIGiOHWM13nC-Vo`^YT5%1zWkW)a} z&bYHSa%^dGVg_HaTm}@}y{_~)6N#~KwmyWRKD3M%?a!VnpyVR*9b6mg*>*9{gV500 z2+6pu7!~mgMP=O+3%D(!@>*MI9N6cy41188h};1py=vo!^C%>cn1_Cd@@v&l(?${# zxC;cj)mFYqAl7Ak0K{5rZ#CtbLeTHej!5m%ii*)xdN$N107H&7^Tc%?4}`452xs=@ zcLNy>mZ-GxP*qM8GH$Oa=x>Rk7;GRBx+&?zY)=O&JYnsq@t*KaAUV#26x*^dUiHKWtcIni1Q7=MkO) zD_DF*%*Klq+#n#z@gypFsE~Ti!})ug!@d)vn&OIA(``UQ*z- z@EWzr4Ma!Hh>4=@2vA1WjKc9;F=WYJ!5Deb`NXHU%@ zJLbAceF}oX;$EFPb?$PdSRL%F#sN4cj2kkxk4r0ZdVDv8P;BE=LC>L=Vv@3Dj`6uw z&8HS=em9xTC=m-P#ZHeO3mY1j9l)jP@#!2oZ0Cx?e9j_w9|3FIYZFyS3#cx4o)gQI zI%r6)z^ES7H75vG+%7ezO!aC`7uI{!%Lfz}4|WEfm){`J<)_YJI_2eyf;xR=ST=${ zj0!+@4v}y}OmZOT^an{>tOxluEI4U-s>|;waf>A+w@;MJ%7pxWw=bx=Jbrg>Q1h2z z`Dw7*>khgDs#7g?<`z2h-I9#8VW#qL~Bo(D8c zBz3~rkq+BnnN=n-hPwne&;>5>l0||Wg+l0pWP;*{irO04qsp>%K07-y8>g!Hr?+!L z2sLB0mM!?Ub?I#sHr&-$jsDOX>Z?ws=3-@eiaJ><<|XQ?`>TIBQ>y0lUs*#TvTZ9ujY%W_TwU8S;8nO%}21JPteTBwtn zE7*6~dP-5Vh{magSVe)wp+JF|)X#imhMLjO)?l(uWs2=B+i)M0((AQqRVY9e6&j-J zi%T^&1gOLFpkT&N)d`~v7(nSNE3HGKA@YPpL78i_BtZf$z~xX$TbP<*MF!=7rO0#@ zz*2t=YnBcw&kY*3NuU9LAnX$?1fck`Df2Whb}*==998v7($?;C9#wV~s9q&~#a) z1)kgjlZapr4$ULmgfbE01~EevE=&Cr_=pPI0Iydo4Zs1o{jhsyAZoXUx3mx+UjWya z=XK`O1=4N!v6c*ng zM0F4*1#OA;Z#wG^+XkC#6xsS7>F%T_feOo1qxGwMKZ6V#hs*{GXuDCi4N0hZ@I$OB zwOfb{n`p=;R?s=W1?ol8cmr{t*@2Vu9vL3y+uxojT^~E{q?3WE#Cm} zd3@8*ov0a_n%nD!JWaFNb)4a@8LY^7EnB+mz#!S*oBp-^c#BEYEEL*EEUd;StO$KF@O#0H0TsK?;K z!otU(3N(D^QwYqWkI4bo+{PrlFMo*0Q@~0O06K%jRwRZ7vWqpWlRUwbNx?^ZCW8q& zX}vhf&)=k4QXm?GdA|(i(c8IloqiWRDENibgBNvA&-I2}ZrK6lvi!I%VL-Ou4FhMy z4@e_Em3xhhzLh13&^K|t+y)6FfDnZmq++WorOoYKmM0NP1h6kmkLF9U0}4WNp$Bz4 z@*S!pPy(YJYgi*XLdsPSx{Nju{cXr+7zTO;r?)IX70-h-MEg{45|1fLk~Au84&j8z z&^Xm=q5DGUfElkvL#YIz1f-;uco0Gf=AAhnuLpbK&_oiy3>6Nzi#)lS7mCpKs{BI1{gh4ELQSd#-XqfFfZICiLJV$uQWYGU+{)yz)!RzXek z!tF35b*Q#svQ=f=!5~tEJUR{CwBxLb4IwLp`b62fu(u99!!SXNm7*i04&%_91lYF< zS8p&(%F^VcN{6Uw48Z)+=GVIfm^edWbKDu@cdp9D00a6GWr$2tm~vi0$kynY5M&i| zf3QICU`RAq56Kb?PGt}rqqxGAJ2bzDTt$2p@`=rigJonvPR5Bn%(6StCoULI=(7dn zOB#vjZxGB1-+7~K3WE#oN9JfxM4q5YWkjW@`kX3Z=M!*)0LGK5UbJvyT{AO{4AtIU zg)a^vzPZ9-8)t25BXlG$MiWrQ%fNYbat6hTftwX5My?Lqahu+?aeyZ~v*N;hwOeLp zSJ#zUJu-50yIz@rU)?ft@?3ctx!v-*y0hGQJ#)G`EuGPyM^-Zesy@||i%qdwk+joJ zH4&{T-J#o8P5ElZc)cCE_QPQ4Id0%vp+X*zVR_ABycP_HaJ$&o%s?!$Y7W?MiQW_jG4b zF`^FiZk>b{avW}J(p#^h)&E>uQ;&iP8O~-I-G<@qg(rmMVPv&VA=sLX=KP87FD16a z){k>6r5fT3ND={$@Dj2c(tJJyLxwH;RA&eR#n}TmUKD2#xHwxM*-_fMdD;V4MDvIA z9*L38i~%m!jIr(_t;9WJh>!CFGZ3(f?+L{&5bTS2EwVS6lM7R#;+rgsnPTfV0lq{) z{15rOXg~lRaSn&A=5V(N%7D_H4%_3lVPbkq&Kw#JTUdk7U20TJLrv z-eCn;1$_?1DO|iI#8d4K86~Hyj*=W`=`=j#iMaWSbPj9ftc!>yVT3`R2l13c)CM=g z^|oV|Q|d>_1YRuHk_@; zHN`ebHj^O;;lB0Js5xt>_kZy6V$Q^nk<%N1$VD^j^W+Zqbd33f0k=2LVQZeP_p2V4 zAS)pqwp+xo4-*5#)YZ^3VG~za%@Z_Hd<(K(HAZdl7##3Ay%4-BI&s5+^a!hJ%UP=^ zp5DmzXdEKFS~NdqW&%B0$w*9xVHyb2%f{?q&hN5C>BVTstq6u{G2@OwNe)K?w?8qIq%xXjI zXw(T>`Z(B9Nrw%w7MDO|rDLbJWg2YVnddguF`5eHu(e|_79WdYJ`htz0uI%2gh%~< zaA+ceo!0!9Ezf7UnhmV@>Dno?uW0}FocXIp&#m+3{M(v6^!n{TpE$P2Gy3O6e>>W5 z@v=uQx~FjTs-;7&$$rSWB;()S6o*k&E<|Mk5GyRRy#`s_&2 zVf!u59%XT0|Om^tI+DBb+ z@UBZg`=m=-rOBi1o-XNd+2?tUuV`mKFXO=@OFRAcV!!Se{W!Dx_=4xUFFjVj$H@Z~ zy{>$zRsYC)od%D3Z`ZJox}=Zz^}MyCf5YFM=dT^ztn=E@4|H2Qy3JK|RxY0W(xkGfEA~xt&AqZ-e#%G1`PY?wSoqq&M!xS0`roYFH*@;%uba&n zX1g%N-;Zr@$O5oA*kgAu(w5=*KG5k3oOICa4_d!tD??}G zeFj?j$#|b0U>^Xj=kWauc7ojo9&X1f=XNZK_X6x2$m4;FyYY7lJX{Bwb&&Ql%8Q^p zZo%Qd11RTZ@QXVhl~bTU5_~;?a^JuoUa_dW2AUfHe=+EH#qS&O8}HvzQc#EPcy5Y) zPm4fj3ck-p{ThMpA;O`oJkb3w(zC(eO5p4O+)IEtjlT}~osaMDQC>gnd!7XPt?>4# zx!`{z>bwDXmjJ&2JPkt{Zdg=s6koXs`-7jume)#rx5tLxJMeb`e`Am~9ot2l;qO!Y z^+i2xkV8vcNOT{{ISRfs$ngP`aXI+dfxH1o`wp}ZBJFzAaV);qpk9~ac@^+4hHTaW zCKqY91O8ZB?D8BSHp1}?Nl5HZ3B>Kn0Bz;s>Oj`bp_u>~I1u=9!=(p11oN?b!w-7X z#6FK84iNGn2v0n4iz)Mm;5j5y8xO=P~!wi zESfwd!)=d2l*5I5A9g`J1SI`5OaO^IAYzj6Lkv8u$xS$NTk5j_?;!!s27Cbavv3Cq zx7h9iDh|?cQ@aa)++phhRqi#MDz>#)xBC1Yz*#i|Q;O5E8zwQt8$j-zIBTk6Y_Dgn zxQ9CtKc{MAm3tVhTYC6fd2zhN+({ZM_{2LURG_tImWgKFfXS^~ezEP?uZ#g`2ZAO( zz9WzLQq0VEDLDYQ*9LBA2%9$m;2t#tTXS5Zm2#CrT^F_jHOmT6z1ostL-)Cv+Ccso z$lZpZifl?ALbe`MmS!RkBgt(@!=W$5P}!jJGix^#EYPl4UG6wF?JU;9I>NEEG?hIz za}Y9H*OZA}XUHDGa;YbY&bKhHMC5qDM(n0kY8m(FP`iA>1n?f>+7C@g%Pi21nYD^7 z{8JF9_1H=*2Rx6!(w*R~3yQ&aK-}u*%o{Aj2r9T7=dUaxfW~fuuJSLdg$u0{ zQdXfS{>zG>YsMiAbk2WS5qZ!zr*eWZ%wMHZ-0kO7wjwP0%Ziu=pXgJrM-=s!6;UWm zvnv9mzpMzJv@KNDBZmD8iwNRiLvMt4e_0WJSVcg243X|%Rzwg=Tc~`Apk0l1!SR<* z1eDc?+MCA$4b^+h7m($M&9cU=6Ge{}f|Z-Sb2G%utz%KFyQO;|yN1(g^x?7HNkEAJ z{5%G+B`9Pl{@9D(jYOO}k_EPByg@IoY)@)eM9n!*})#rE_A07QrGLd|46 zbs2_bBWp*IEXn9hiaS08vle(I2wwlcBWR6_193vW3FODtM&76xhgLk`F6G1sgB53N zR)#=}13Y=B42NSbWiiNJ_kV+|3}Rx5?*s8#PeGBN092r+lM{6?X07#Pnn{34Xgv_z z9H`OriHVLHny5S<6a=zcxg1Ef9%o}M4M9sQ@r$#UIdQGk8H8%pu0(`tYyQ0B;`)J{ZDe z2qaa?>SJUvPhF7>G4G#1OT`YN+77uAep<%8!^ z+4=Esy-OJfBpf1@39(f-QYGWDB#MBR&as9ZU9)e9clCx7<cL2R_Ji3t?+XPobhU6!n_y-`-ejFN8Ua@5~2TO|`X$BO# z3X7Hg+}h>DipQG6LmpBF1A#j9OsMo~=0t*(PylUfkSYMFT8~Oe$r^H|wZyl`{UA~6 ziKoOfDkNiGYT#1#fea2RnGF{|!!{Vshm%e@!U4II?}5;vHiRLtNfZ1uz#;FN>C=SG z!Mhc*-lgcGtqJk08RChr)73z{x^_ej(`mFvjy9#b#KM~)$ekeOh|P>umUycTD0_iY zYwMEXd?8mEQwVE~kMIhs7UCqc7puHYpQ10l_ z!n*Cwptn{eEAi<->}^em7pV1ER-*cz0)ZM%0!nXS#G|~q&ge-mxl9;z;**Cm7B#!R zfYKY_I0b0hIAcy)1kIQMGN;p}XE*z=LLlK#Su7H%awNrmlt+fy3!CRFIo-{1yF6^@ zR2~2cM?493xr`spX~!|BnQ>*zi$GCpLNR*l-vDH<2`IK_3@9zJm{B7zTh1Ec-2`A9 z0F13PM^?tTAf7s%4)27Z6lVdsOYO+k5s^`wPk?qA(F*a$8;oLomDwV7+Q$Ld)Ngf>uP+{!qR ztL12;3C<#^or8s|$7~r8``64zytEDFifyJvATspqiCEj)wPTTFVtfZ@*ZLvYO{$APhDUVr3@%n6Vlr zrxU6V|KxokQ$Z**c0FyX7%Q4lmEpO}8It8d>i=hv;_dYd5b5=2iI`)v40{5`4ZDnu zV@-ehHz0M3FOw04Y!34pxMG+H?ac7tcLC86kI3M(2q1DvFE{Sau6Kdb_s^lki|B$Y z;L`pa2~$ApfIP4|vU%4D**BKjD1+E*_~;}UDD456Y6?QzH58OXL+X;8OW|UiODXDr z1!~8Dq8v|tNDBp`TjkSm|7n^-&DH_|4-apO^Spsx@~YJg6JBndRBHuK7w0s%ONblP zco;(L=ydwIi6_sG{cYGRSg6ymHM(}d*wMpB4?|g*5nEH7HI+Hym|PytpkNnODza32 zS*Ougs5V=fE!Eg?*h{rtnysI`liNvIWIP$8NVs8}a%I&J6E<7NkZ%uR9&gZ@# z;nIAlJmbq9lj8J^Y+mYM^U74NP)+Y#719Ze;Upht%pu#d0*ME$^!yrS50_JKmw**96yRT#8%ZXLGAl8kbUGn&YC$qlUHG`xOB1{)tW zakP##<{3_$-7Cgv3o6+}Pk=WNj|+xe9!(u14`hRg)2rp<*aa>DFXUk%qo7e@x33>f zi*r8Q@rPrwfJhUYBK1A_XjmSY=23iX2!!?1Z1qM|T_JHORkXY#O`Qb2ghoR?*o?{3 ze+G*@%#Y2@a)%}Obo)v?e$7|J(?carzegPAO_Q5;#ZdsA!?E(TY8v;`rUm^WcbdcY zLDI1omLA=(=J1?b58bxqt8McSJ^$R1$19H9xAw@|`G@eus%AvcK9J>7lOp^dj4S@_JM)pHIlT6*mEMIc?H%*f7$-A8t9_-fk@z)^TeI=uX`gwjA!wg;1r z&7KRn9okrN^wH(VRxUoecKwmrI}TMm4A}xeg)|Q>UT}EsBFgTm`N!^`e`v`gak4vB zvF+H(TMuo#>*%^?rN|C1fD~q-n(AapS(n(otEQ+&o|$#*g%w|Id;HM+-M|FI3p>E_ z;bpVQ<=SU;kx@oF?}*Asl9@u54$ofu)%HgW5iL4au@Foj+VJ3!dp1H!M>pJgc*(Y^ zSqo~EQq`=xbcESE07oey>8sth9bL8d$eJCpx)jd*@4?HuE#+@Z{_;RwS^&d z8jq%{C6&8!3$*ge^+mWo07uazRJpUTa#eZdDxc<12NmSvlv0M*qlR3SPviI&ceECG zodMWx&|Olw4Y|6RY9*EHRIL!_AVz8XcKbA(o2NH)g$jeASXrm5h3Eu)l}~eoJ)xjd{Wd92*7I@NOLzEy?(pad<_$*O7DT8Tzp{91Vd&VZw4@)%AaSh=de z$HO+c1!XyvPfx2{pKGahnToUmcM&Yws4OCbak4^cQRVi1yICEhra{PIokcK3tWHto z(>@=P@rcs4xm}=NVC3w9dcqblu z24g-KPBa!(uBm(km!-Je&O-EB9-Ib6C+hb3)Nvp%ya1cBug7^APf-yuk?Y2`UtDog zxiz;S==PYS6jh&hVFga;vNCGUW31AS>Um)Y!8-uwHrID(fNAu_6OWv;VuB1yhTBf!XeGd zHK+^7@RXnkuL7uz*BQzIduSYRUs$;nhb??HRvO0xK(R>H6z~&@^4&R*N+9Z>+t%1Z zZEfx{@jq$xkJpI~S8`oU zrf{$lhb=vR9CS7gvN1SBIE&w24WXe?u{@_2ddVuHJ7NPIhy&$_;dQY$t{$kW(~Psn$$rAqch{?T)I#)9t%AFSGiI}O}&-tatk={AZ<$>p|g0GgAaEuc{SW_ z1Wv(rKH8;nofOHQm3v-rs1rFvDn`Y?U*$TSM01OfCPDS7W0Vn|h(k)DH zI&qLo=Z)u5y>8MVxHnA`^ni#^QMYxdk=}49gvNy54_<_|3U8*XcI5KzDp*y!%RXkNy@nluSqg54;S5?fd zs@Ppsu?(@uk<~knK6w`qt12F;nq5&ft0Km+smM_$SIvI1YR&^yv!Ab;^F-C0O;gmW zIkT!}uc?~7x@yk)s@WUy`(eSyGgY&XYlkedUR9tU@1 zNtS^M&IThJP#D5L#C5Fl?D=HBqG~p3!lLmbhIdidO+sAYNtcp%z!;!HhJuII+;Mox z##);RWs2|u0(?pag|d!@yd`V*R#mL6nmrq>M0pvd*?vqqxnS+d*=tTbF-twZY0HU+ z7N1x?OZ|G=#^al|omg3M;^CdgS3RtrnEmvL2iKikvXo#amfU%K(cI&!ma8Y`t~s%C z$??VOj?bTWeEu4TdVJBc6U&zZ?)b_z$JcF+wJP<*(k&-$U8){mFze*9`_vP2Do(6e zeEhMU>WK$7pSXXsYBKWm=2^!de;T>!@mseYzxQDRovhe={PFc5{q?4mYTEJb3y{u& z?z~Twx@4YueBRvS%Xb}L{IE%hh+yo*gPTzc9YL}#8~@}3^H8s}6U*nKE-O#YS$=X! zv@R!?E&ckrT@cEw6Z4kV)&ML-+KCXAkjcpB2=`1=OZP4-cki36j=~vF*S?)_ zpe8FGgy7{qXKp!sPkCAHw7tvJgR@p#?=CNOdY#h@(psrU_i+e#i#2!_1PNdq(M@4! z8dxtAx3?JeE7n}O

Q6MF63d0@jHkoHL`)S3AW@I*K*kK|Kz9p+C@t17#0&?6Fm!&t%1z84 zCT4y-Mlc8GCi&n+aD+@lM`s3anlAnvrw3<8MdT*ooj9@_6SqafHc`bi8MjrgD?$_? zx|hoJC5R{)u9`JrSB8rl8To-T*^ywdMmY3DXVa00aMS2Yw%6JJ$o}2xfjRqk?%%!t zg#)+m-?)F*{%r>qs{5bYzxzN1{+lh5cH{R8`?oN2{}y%si%8tDe+x2^0oVic@$-cP z3qgP|yB+HOCq(A62j;5>W&!$nd~P`~542|=SfB!G)BfG*D$1C>e+RO5@86CmP~MCJ zHlnEA1RxVk+zslWs}tCVzOC~4#VO<-*fKsUC^ zDMCp5Uj#4P$P2}es3DwU|WS$P@&DD!lEo# zDtG!ScOqQhRp@o%lMMV1Cn?iZyJ+e(Fz&(tnY9j7?(#eFfe8cET^R5b(s8>ngk=qI z>kR6OSxWRLcCA3Ub!g$>GkWptA^NS8fC@Pv3)z zG-*TR&N3%P?)aeiozY_54Bc@JD9-CUY%MTf-OHFe#>90#-eQN*3NE)8jnF=BjvXF0 zVBFrvyH(7|X@`nc4KZ_^!E^Fz0MqTfq)gM#QcHixW88Q--f(?hT_0456`)>XBAW{r zX|^Hb5nJ=1Kkqel>1Vd9Pjstst1aTie7N|}xa{EqOARnE73(`<1x4DZe%*)7&cp7U zjFyWO=+bZvNc2#;xQt9+inwHyK5cDfoM@8yG+P)Y>eraYF6D4a9DRwAmuuYECAbm= zqZ!0}ync5`6qHQiY8rVz2RaWS<1|cx4=DCv1uKoCevDYKbd|>H%4IMf-RD%0So4T$ zM2GDnS${1r57vPh03ARt#OBa%7n;Heez_uIt}Y0YoY3QSIlSV_Ve2bL+-e#YE_ex1 znp%KZB8RV0bh$BCBW~c3`k{m1(y2749Ol`a;QM^swgGtyebNP;HUOltZp2oB3d!{# zgH5r}qyst<0mj|zB*d%3cO6Qt6%@c5C%$~SxJ3a=Y74GeQ>#rz7>L35nNz zMG*y%z#u(lIax1>6&B)$GjQM%V7cxp9Rlwt)2|p|yk{)?vbpGN0`M>G##xps^&7RK_G~n2-UM;6 z3z6iVG$KRz9|wl4SP~WDhA%Me13@P*EP?EW4H{+z&c!XX`n7w;wH5MW2#2jzHhid| zQTm;-x?XjIn?s8VZGoxCYpkVw)79emN*i9SCDz6m=*np-v0#i_o~UTectaM8qF_-k zzP!}ouq9&=&h|IDR7eX!ByN0@Y6=y>+?@0*!LnlN76cyEUR9*w1|F=P2_StS@33W) zSUf6L^${l{n5OC%$QzI_g~l~wvCa>_ir(1dfmi3aWRVVA%W)WUiR(V-?+hg#s}xoq|1z{h3lNA~o>qL37{v1WUwuB<-^2sTZ0N(`b# z;o_!5jCrKWKziIiAjSo_rb@3wmZ|TUc;oH3xUDTl475VrWX+3?^97RdNbt|-S0wLx zx8krh8SBo6DL{K&T(043rF+>r8&Z`ivhx`Y2?{#W8^Wlpy9l}&D7tJ!e`TUX*Q{f) zy4H^67KRP?6jRh0ko@Adr+B2n3ES;#1urY*u-%-X@z_Ngi~pjl6rBaFHi(usZp||9 z)`@K@IQnXh9rAH@TW{@9LdO5HLXDa_;#x-Ta}f4wX$(CigvV+#NZcPqH$e9h+hQ3q z(U6k7ElOOKt!Ci%O-;ojs(!Z=FB|M&D!A;E^$jo5v5`Db^e&~n3G1GYDQIjQGA`GW zSfXf$?J5&a7>!J}bPsGSqYsKkJ?wYEP-_tpL|vlnJjDJKT*G=6gwfNXcQEZ8{f@2$ z#-0~!!-=C4jn4H7TxaI%y`11!+C9x#-c~u@k6jfa-p1$y>z=p)No>y`u-}bYZV#3` zaPvRhpbYFCHhVS7h8!3VSYxi{6MR^N#!dNpq-q4q&5U#zO&iG<58~Dl(PN@3klm=> zZ!$)<;idHAH43;J&FE`IJS(n<5)duT-*BMVKG27U-);-AFbzC&A@JgI-*QX%n4_7<}okFlXP3?vx!9!h3NCAV%_h zle!4^qW28z&eCBUIo6H0Ent&?aNOLlQw%M@3J;{MV}hgv7c`(*B<06?FfUjZmtq>C zwOuH$+%rnnqddU?#-shE0O(Bg=vUk#Xtlr`j7w;5zBK)EIjmO~dWwr742BYeje&~s zPKw$_Dx)>ua7@(cd(ZFw3sH72Q{C{x$T75`pt8W)tRdn_3U@qFEg)x zsOkJ$o(FU}{s!4_-4wnn@m-ET{u{!NWNg)rKPMl1>&#S~=iseM+_BE{OH*+)fj83( z!RBUOU{ppjN@jH;qkzC8>IMOl3E~h0PqzCMYynoX&Wtn!pnU!GRE0-S_#Q^?N*;Z7 z$iu`YWw}Y)kHZJ@D02mnN1VCj#K^4s5OKuF30d$w!)lQ0a%OTP!8p&<7+ky!w84KK zt$O(<&yG-h^KnbJFQyq=Krd|eiNdLyajXxUdg*`Q!R4*%a_=c#)*&H_u+YPSMhklGqColzFd(|YjV&6~D!F#|ZBH?Q`|x$;V9_uTG1I`{0_&7GOmvt9MVu*V$Ot8z|zMwRb?V4Boblz+oLJp{L0fWLlZ3F$+T zK3!++OYr$1{=!I`0@x0CK8(Cu0rw=*J^`K^X>E}=0%`Z*dmsLu0!%059YfmGdN^nj zf8I?VT;qWo7wnd|a^#3(FL;M79DqkSKKbr-a?w+;_F@>t4n$d5NV@Wi^&w27JA1p+4*)9N?1of_&Og!_)Kp;WAYbIb; zp)riCi>!iidX0zYitwKkte4fma(AGm*M=6);u}C{UmJqSQY!ocUe9VacC4+lOXtDQ znqKvs4s@J@KQnqfi;n@(aW;r1tFMq%8mS+Rn+vw`g|3zhy|t1`-0-K!>e-;jv+7RK zPxqdwT$9xofr4{jJfJuhG0qtH%Ycw0W4@X+^9vw#s2M4qt;^x5FRK~cWM%>YZS!p7 zF}{e7h~yAaOsI37KEP>E4nWe-six_(9U^eS)$ka#Vl-N+aj=MvT+Y8?s1!ZqBVRW| zbbW*>Cv1)NL7ZUX-V1%!1269zh50Cw6dBb@l~aMtma%s;(2#<%Nxz z#=*G^eGru!8RBf}zuG#)H-nC0ORgC`$1g|pEB zjcq|3K4WDwDj$yQs`D9TuaMfHug6GTunI-j3rZtj-c^t0HWrPem6p@&;15$Ep<-+* zBEPvZ{K7llusF_DX{>u*HWo9@SU5nF3r#5DOCik4=rggcj5#H<0DacYcAelhy3mM8 z6hz@@4=Dq2QcH|)k(TS^)Bu%BuCK&5I^R7LFf^PC9AZ|6N+@RI&H%0s$6j4WaiBBy z!}26zJSVu_o~$D9^aapzMV7T%GGr(%i%Y}SB%DkL8oXGnO;k@`v51m_Z1tmGTo1-- zo7^TY-unR3(Yc|vF^ZR{B)qm`d@O?oUph-sExAt^lx0;G?^2sCM2puR<%=l|7BDV^ zg>_7f8kzbk%Xq40ksG3bmb&qV81wX|fHYbW``ECLn98Hi38u;QGks@Rwmt`oMKiH; z9g}(4(S@5FzsHR|6gmU?OE98dNUlE`>_Hj5@F9FJ8C{21J;VABr#uW0^5w9Vjt9GX z0}HK)dP_r4LaZ^WR73M&8%HkYozAlDaQ-OXGsYBxmdnQONdGvge1f+qOH}M=%LQw! z0`FllQ_viS(F2>MxJ*Bzuyp822N6^?*BQ1#q%ehflZDRWq)Atsp zvf?H@eT{H}8^y>8)-^Y33c&H2PV*-iH@sh4-r!#)1!^YD{t>8pCR4m@_n zd5*_hO!)Qj#l>@nh*cKt*8%E_Pw;Nb(?}6FD|)y?<1S0 z?VH$m!@k=axnCRK>e1Ji9Paq0-Bx(MIGy?g6x*Ct;yiuws=lc|H?A5p3uOs@`ow#k#(!%aTl0Lm>=slj%SFd>c+N;N}zJ7R}6EBUt ze@STkZ-F1KQ;Xi8wE1h7Gy9Ey=iJuzzPxjv9#eG1jW-ls)o)Kpk^7C3hN*|jK3((R zjIAY|X3owVFmqpHyea^(`49}90=T(0jBDsuw)(mzJCPn-;g%!d`0o$?+)PC zMY&A@|2-niL5K#20&W0)-wvF0NIQ&Xcj5b0@KT2BZoA{Ks)C zr|~!!DR2GZge!;K48(b>HAe<{;upud{D(=`eEi4IJ|BRL&ac6cj1vg*&X2KpHZLXP zgriI3W&s%&>C0Q)G$0NVL?j7wHaPaO5f6~M4FY991~8mJ=CF@U@rENgaUn08WEy$l z?L%aBtwdz)@_@$MM1z=l<<&GC^cq)!#*+#vZvs)ji~r9d29!>a_{F4{16K1fIcnbJ zWel~lFF$Gry%nXzHyJMg42by?a{^`}81*AnPLA~g>d^Qm;?<&K(5$>$ z$f`~pzE4k}8&WG>AeGLGTS^70hO&7PBDFy(GpDx3K}V>MTzJ?G1l+?Pf~HCJk&0TK z8%dw(rlEWQWYyF*%9Z8G`*#fSH-M40uL&sD3@!nvOJ1=>`ACb61qs9m!^$Rw6?-8N z7Za!o@ptP6l&ewDWt`IDbO9G=SZmH+a(;+Y2D~7OlP~iDSnVogdFgOhIGb*yVK!^^ zdA!k}Q3P7@{vc8eDu;oX6^m#rJMcCc-jFLL7=Qv$o9L;SMl0_GSE$A!#|mgT8sPs> z_clM8XIXyNuWYdy$wCNYEDP**O%L5h?(B-ps_N=dbb2CRDl5kMHW`s!V;G2eGUAEI zn2d-g{5%m=88et2Vu_F!mSqXCF%kPlY}mjbzzSJxKnSl{g7|#T%f0va@lgp+3e514PK|*${~C9c?z>%9n--H<39_F3+g) zs#ckf=__pTUVIh$!_3_#?Zq`?k(Tiv(d^&MW@UNlZ}%O8v~+kGs_}oM!tZ=c1z(0f zmi+HDV!@*||NbC%=xfQqgw!4mRE$GxM0j%4{p;|i(tp3Ipx-Y%6%I?AdrOQrC($2T zzkdO=|188Xp7BeX`rT}5U4NBY_eVT#{(G8x{-NentHmR-ew+*N8Nu*vEy;EK3d53rXgt4%t7q>a+1KPoPPP0S?g+z z*R0D~_fP5ScRtjW@IjPaL{WTc#<#-lrsd*aVx>=PTYpH>Z9 z|FB?0 z8XdOsFLStMxwJH!kGGEO?^6B#$5u};i=e*k{u`S3onNhqy+X+JbRSOyXbtkYxjx#c zPf6BeD*T$NUyYL!K@V;{2wkaPVZwQA6b(s-U4J2?FT=VCQX+u%z(1zyD^+d9XFqz2 zA9{32Np5;D?sXwndohtCux3fQVcGwcW{FO$w#abp-t{QMr6N?60l#Ei3wU_s=MHcUVkl;O0%?%2ey$pt$+r z?bVzbpHuMPP{E85th1iPmwXcLKc;{gf!7tNs3bZu1nYl6^&j`!Z+U$m^ZpkK8z5IB z#PGF#%QBvUlun{Wtk1jun@ZmZ@kHl_h$@uqFR5lHu`ES74O&k;I*EIV0_^TEENN!; zxk`=Oil9QZAFr$SjN$6+uAYSBf1konhlTq<-?I?P+8U}L^c5;etuO~GuK2$zK788$ zga-d$*r4VuYw|nt-CniON~O-J$!8+o-Q$p&J@|I+@n-fu0xrH zY!Y`q`NO_5yUe71#q8KZeYVc@ekUoNruFXokC+#CHe{~G=zszH64Rgp#+t8rT;%xJ z9>OVmHRwPWE!OlfaXa;|?+h-iYGTFeYp7h^mfSLjLsFRbIf8#jV%?Z zjuXdi|7)d?Upx$8|M*c|h#nHf9kYZjH@hG5B=u2UI3WuFZx(WKfj>bY1h98ZIX`{R z4M<$#g^p(4ip!T-kQlCyBEYAtk8%=~gD8{T@&V;l9>eaozr<#TkU{V-K3*h%ldI)7jZkPmRWUa&At>7|Q(dH5U?I(*n z=ck8+HC!BD-Jz$S9)Hgrf_FdtTUIVDL|g>@0Y0RT>;1l;Qu0FemetVzgodM~yvm7Ir>&&i z?!-gkGTI8n7qjZZ@KE;M@0X`gOAc$FT)5-#Qp`B6pMhPPwOzTf&FHzczG2(hHR$uBXI#Xx>#LZ2fp-1AvuE|O z;Qr9}8>=FuNEeqxvUKkL2{Sme3ttQ?nTu*_+v1lnU@?PB`MUpmhF!lQ8?pEP8W%>B z=G7aFmHK`1+3f`YPHscMX4K#>`-GB!gwb7>p8w6g_GV$pNILLa=Bj=sVsT?}33R(R zqBv_AqkUW@>b=zP1@kT`BO><64|^q+LAlLrv5x64XE(C-t6(gOgR!+OvL;T|y)A(PuD%f^qB8mg1 z=ahs!?zn3NF^h+j&A*p)t2nh)Wby^hFbzgh72}X;h_nR)cnAS)W~ctR`MGZh*DLRQ z@{J0&HEVOPOXA|Po}3`L*`bX>lwpNE zc*RdBy;b`0-yoYEEXsKX7a}Z&yFpzMP8a{3%7ILfD}D8RSMGdr&o0EPI(HXf6Ud!x zyGufuGT4w;<&u}V*UK~FXJ`xe@a|6BFs}^%b^zVkH^0M;(ey8>$I4RN@r(PseU})9 z6k*J9xZ4R5lMAOg5~yO1TT{U~03QqTm%cW<0EI2=MO=M_$OL7tffRya&{o3q&L>}1 zA*fIoZ@G91IwkR~06)3FbrAIWxO!RbM>RqSj92j-Y^gw{J29Uh{Du*~-!qoyyct+8 z4b|AV3RI-+91>Px>6H}ZEdBnBq$1CpW=n#GG&Dm{S;{By_i#wnECx5O|xR5bee-9!Og#YjGWP#3+S4$JA=p+mFsBPbE z95O1=+sM<(*Te7B3MsOKvU0gi6uV>0f!OEefNqRO{(!VTb-1;R0!t4YbT0CKT5lW^ z1X0qeP7}>w2+jO0+sPP?9Kc99C_Qek8zhmt|YnryAS=af{3jpv9pTf zTHyrh81F`+Nv?jdYp&M>ud(~c?k0?jt?sm`y8NcygP68|@X2r1;jI@`|MIv{5a?l` zfLw~mzEdk2zso(~WETV)l&3ilfiO5tMsu&fnXTRu4&;Qm(pPWK19d_0YfdELg3eX; z{8>wuQ^9ZlVDFoqFShQQJjc(wUwp~s%{ofo*S^tu8i&8`5KqC{gKYG#&HpIx(8stM zZ**PvHsOjeZ7@M^Yo#mqbHa2t1(^#Xk9^qi%nd4X_jNkYidlNy^V5^JoMO$}-GS*# z`(~*ipuKGpmQ5O8twsQ~|rPh(e+|I-h&5$L?GA&=KFJF5+C|Fl19 z+TUz8Pjm_yPHBbWQulM3QRZy(P&0xGqS(cY!^7((zy=}CXYcdt`r?g(WXua(reSG4 zXd2N))49!VVo+MDA^07$zD`N;PX$5^se-XT^&l`q&^4ITOdz2*F$ZPoKh34zLq-|t z0dtG53h1r2dvC}89U$>wD8rJRC~hgC(&Nzy&6`CYj%&OHTAXhOkiW-WlwI&=+|Si1 zQ9o~)4d|>$Y`qQr@w0Khy}G3zVEAk32L&)f(=FZndZrU6#Meux(AxEByFzAq{c5+8 ztX%iu-!UE_@9Sx~e;!?(!lD0p^b@S$sUO03${Bn^Sia#>4i}()6<~TG8hcLcmd<`X zs2KOBZt15*kmQvgzqLa1^jrbK|I9l(TwLBPB_;it_eAXGlWU?Req=|ejc44J{Kcp9 zi=VvS`&Dq{YIgEx562<}pe((0h96)}q92>HyO!Fh)-4>lE!zIJ&fYHAx-BaPlN&Nv zWu6U2KWw}&1{65mBztI6KD1fdw)J~VT}=-?ZrTOIo}@Z#YxwO#s6l4KS+5i9hArp! zgqWLIQ-7`aSe%?JIugIi;XHK0|01GkACrbN0-+jN^4EyK>xJMc&=1puqC=@Zl`T3k zCa!Ate)xDbY<=DLRIk7CSz=u$!}O2D=eGJs;C5ECDjz}cK5}#)F`_XQDmu}B@pwUh zla-15i?g|8Bl`7ks*l8;L{k0z2u#XqR^|V9+_q7yKTU4{k`GLMym7R6+A~!t&?n?b z@)v})kp1Tu{$|J;-mIoKBit&vA*iRvd&_V?N^shI$cZL~T@(CewLBat=|1`_o}Fk| zLk8xoB>JfOyI*S`7=7fR^6Tkj16;t&7LC?4B63d$CVNI)pmb|uU zgxMzDgT3E<@JYudUjD=Dzxz(%0PlYG^SfUvVMDof6k5d z-+aB-{r>;?N%ya8lmFms@rJy!AO86cPv`D8pS<3E#NYpb@BjJV`t#jy{)c>+7gM(_ z5$FCN9USbxoGrWUCb~&U-0${(IU_9QV|Os=wnYO!pqh_|=)Ec3JtO*PU2ReM(YSQ`v-K&M9FRx!1-sA~1U)H3@Nw}{rlvK$;QBhM@?s+G`TYA)x%Cj+ zYCwjU)O-n~@I}IATL*!O`{-2R#B0*C*&i($SU%&;)aKJpxIGXRm!H~%^(L>7npDn9 z4ZL=HsJ?G@<6>;6RnM9&b5(!u6Z{j^OcxN@O?&Aefw5*vG11Mrhwn>NlA2;=Y0Wb_ zOSY*~g~N||RNT_7f*wl5-(=@I{KX|gbbACbBj=SYM60V#E=qhl@^%M}aE$C&}#afWJ*Q{go{y#;F+ zXY~WwkMh5{y1LBQY=|bzYR<1I07WELX$#Iv- zcSpN5yj9oczbsCq<3^t^43WnfB1Mcvs|-lS`FrtR-Yo;J)BYN7o5?x3!{bX25Vsul zLhrhk^R-b zSmR+W>kbP065;C(c%0pcMVt~;3k;*QUZg^~*=;*FGwEWqbi4lE+1}0h8|E^a|Mmkt zCoxV2U^3nDCwdtd*4aawP ztJ`*L907kjcl#(O$N~$hC$2c4Omo%rBplV>PEt3@@w*d&FxX%_PY4rfP1rp&6K!Pg zW2%auui$AotD6-tk{aF{DUfyZr+!qN>fs&ngx@sggI zdp4t92-K9c|BkK?O*Ua5_+gAXdNy0W!~gDLl(W$e`C>EN`f9UcToK+xs@MXvoFPsC zj!6as7?Y78FAX&dV`gv;2o`~PLk_NK{=CU3IVc^KP{|SB@~E^6v3mfjOfUFa8aGL& zwx2J;O)bYWS}2Od*mk(Nce6SjPkcKnKjzKNo8(lwMKVH%SJ%+(QSwI1@-s+0&YDE_ z9MwNKJpxS9BlxoglDktBSOcZm@x9r1nYA}M+jbArDGZF_`iGPIkrKn z5+PXfhM3oxqwxU`spux#S@(O_JR#pbnsbKaO<8`JZTxHQy=eRW^6pc_;KQ5py;Xkg zaRqM4(TD9H4zOQkUNrIqteP*;1uVatFV$M4JO0#UosrJx;%&+vTfmjhRicpX^b7Ort30m#JdXWh%X?u6|0YOyZZ^f*~>jxZ6 z7|a7l^WEj|cpsx2M&?J+T(jv80uewp6F2h&6O*hZB?s59GPhTYMU{ESn_zp_VprFS zqnS9jIz2du!)3!C?$^|(b6#>E*WH(!*f_auW3*dyok!IUmfFYNw;o};v%9vP$KNgE zM;bhu7cs9*mOMC-vHzCUc#90$jOpq8;^gXWhiJ{oNm3qYbcrw4XhdX$W6LP(06Xh^ zcAh)&plT1h_+3;WDN;-mjmO8wLdoyeP~M?BWdzQ`wI@kq^6_br1RdhAy@R*}>is_C z`UjX9X-=$^=C?yrJRUWYqQCfBu4yKw^>@x3oM;~j`)Y!a?9;`uCU z9ajxo6j1VLlI}nrGR-fy*u}cAp5J!|-}eUJpLYYS-@T|nLpc@gbn$n8;mtqep+A&l z$iCLw{^C`k(UEbmvK%`#Cu_>axL)(!e3@T^0mLBMAG&};0c`` z59+NV2)`c=lHU7Xs>w+3I?$TDVa(~^V*Z|pdUBD4`JEEA9kyjNqh&w-1}|&-@u|`5 z`y;``jn(uMy{3t2u6j&;|7Y#$L3_!g@xu^_Qy{mnCr zsb{z%a&n3s=Yo>;9_$R2W}};V!HL)A@eTan?^Shn_n6owuJ>i6E3^&s?%AnAE$|r^ zXu7@qy~h_vFBj;&y|z-2BhJq2r#(9rp9hCLinTarFvm;`8k{#(%KjQ}orAm<7_|s- zRY(8J8Ba)}@3qwl`7B183(-$yk)(bx2sKcU?87NBkuxcD+)!WZQD~@ zdSZK=mFKxzXarrPD63@;0XK0|NsfadoY==kbY<&H&TmC_Jzz(f24=hVG9It^qM*UW z{jnD5;P_0(Su}v>?d><-dY+^7l(W;})!=4a^b zbuKR^GQHtw^m=)kDnRM(Q!I@|4@th2FZ0dq^(C4O*;dphyFf!__*}M{e@Pc=3ec21 zp*beN_j~CMxVFS*%acS5Z!@yLb+1Dy;ReW|fY6+RMli%Q>*VihwSGY_ys~QbK-YsOF``vhtUbsPCe4oqf>=LCzBAd~q-Mp3={RP0+j>?6G;jhxs>rlu z=N+d%HC5p#{a`8iTl!#7Q8qa`HA27Qn8iuR=<(j^AHy1;z{?vE5U_df2PsodLYleB zb#-GxDB518d;Lb0jfMETE4uB>OM9?3J9L;X9Lh|p8J=PS`~>gWaEhOqu1SQ2C;0+c%9-c9xfn14bhJkX1b${lfguip+MoT@$45^QNaj1*FS$d3^8rifdVUxuU5?Vm*D_vkzR3aTnEoNMWVt24m z5IGnBB|u8x&?YMTu}DM8k>n7CLiX8c_;)unOWfU*X8pXAXk`%*n8DdmIbg)wUa;Zb zld2bqTxF)E3L7{CUHciqS8o=Eh#;rsGZ)-*J9{mXP zGZS1)eu0jLwByE+<<-s`4n~s-x-bp6*ToB^i?Vo3LX;@FY1n>rx@={*e2 z4{r3YHVBLn3OYE5lqD)CRri1^cZ$|rtaT$kxHUstgfhlYa;pb8qwalo=p?P%o6lfH z^&3--FW#!A9VqsMQ>Ze&I#m($rH*0iB`y)>Hwrc@cz*eL67)iFqwQUsyb4prn08=? zE#Sn9pQxivr zX!9dKF;9@LoWs@1PdKCQrA$1W!z(SgEV7peV@dRpj#)X`j=`cz+Y>!v)LDH0LWi4U zM2-n1`oS?#m;`q;$tN6s1-~o&$O3ke0L;-H8@g_Y_ZvFb+?{RK-o332%iY_s+=g=J zy$#)ZKL1Q8VcMngL%w;wyNd0rZsw9?(zp`@Q1;v$EYV(AJRohnLT;5tV4!~5!RhMR z;$rd2BPrn;(yI}8QxtaLeQq2u@{(b%-kx46-6ibEG{#+YoS9g>#gge)g{)EMi|XFj zJw1I>46vPfvei$--1<>$*{M-2<7*s1*Cf^JX*sWL~q>~MLw zZ~n+Un^{DTdSRi9*EFZHGThu$-cuya{kJm?T#u!wLK1$0;S+JWpXfl%5Hn0EG*9!R z(x}V$m>aHcVjkUrMWCvK1XnDD4SEd7_=L4#!_bY3{Y7ahTmyQUQ6;lXa3?nR>Dkpy z7>3|>IX(?#=j?R0>VEh`N6ydQfBD&GpMCY^{3lz3w9nprHA;K))t99CC6j6-zZ$r{ z*PP47lcWjivsYbNnDxUut~TSQ>y((%S}q#1502R zPHOq};~mvYv8h((&Pn}P-x8NjYO(M9MAoDTFZ|j`Ew#R}dri%YKK!)3{pLw+=|GLKS=9@JtYi*t5u{-pVh5@B2mxpSP@+(M~M ztp_02P-?NkJ(QYJFQU{mzlqX(+f|hMUGAdPBtOK;>$s-X+bA`yZ0J=}P@clgr^_vc zb~HKMNU2S6C8d7czdShDV_$vIZRgJ~J7h*IIv7jcp@`48LE#Qo9V7=E)sd08QVlAR zE!?d?v9Dz6=UwbQBrfTsB+h|VUGYVam4o`<|NP)UaT`0)#&k|{*l4@N!+SrHYA&wN_h+kj*b~p8(K47^ z;Q&YnM{SJ z61W@iFQz;+64LM`YH9%jOId*YIjcY4)Sri1VtEx7n$#6K*7djZdU8BVvcXP`&9i47 zY2EDdR0_XdV#?*xZbA{dqtlf{#iKpLkCosBFdM}HBlI1}b^@R`-8Opp>oJhF%gPV; z{I(;+FuAdO0>x`~_u1@^Z>;f^5CJ>OikRQ}N#6PCMT0}fmf!;+pGyZ^>;*Se82{>9 zY@L;sB_!-fTu2(V1ChF9zK1su^x?_6Gq3516S|1OeCZ0TmvKNJlFcv7F|@U~-q4$! zuH2xzvZLt!e0d(EqaX+vpN)q0v5o<=*ZV2+Zr9F_p!?09V0MiOu z3_L1xreDLvY^$Nqj(PbgwEfz&qs5_Jb2BV}sOT>g86lG&keygqb_di$X;7X>6R&ma zXw8KZ4dnQm$AqJ%+F{CVJF@;Onb{8-P-+7Q9uPh1%rc?#ji??<9I2Z|OQYQ-X=XwN zQrwyRkZmkvT)&ipqe=yW#$!|{Fv}%gTmNk+A6Ig1UojiD0S+hErhkg5*pY)-iNLK6 z4s=~^e?~CehW#~*&7RJ6=h--^+^~NJsU8i-uJ`+m+HqcwGt)V?898&9(7|x%6JyRh z7ee?x>=4N8ZcCR~0(wbNYWVCwj~3!Ao|3;)7`SJ$RMP7ZxspKxQ>T$vQb+9`bIZoU zK%-F9UB#p{2eVKPW34=OEuJ}mfWxb#Iy%sU3oAo<-*PL-o0=F9liNP#;G?{t(K)5C zT>t5ID1`qPW#{)P+!vjjmE{#9gP}O-!!TDL*(|NKs%Z>wg(Qcm+yhSQLLz(x!Ca=l z5p3z0;mns1D&0>l*4xHr8-Q%paJDX$T6aRUSS|nQz~N2>{1Zms(50Fd60YwY-+NxI z_ANXHe_%nJF&uMZAL#3FNPkl}1vSLz zxQT3E`df>?u~q0P=?H3~n&2FS|1I74OUSQSsiFyl&S|Lebby zxaW5~?tr4_i;I+*S9jPmA+ngS%pLcb@q^cN=K8udC+{HDlwm(L$9k-v!-DSE&hEP7 z!M*RiUma;DA800dI>d#q_pSVF(#|d_&`VH><_1IN*)pl{x;)j(Q>x14Z>3|+)op%= zN&Ri)|Obp6ks-kta7Fkd~50nUlP=aS715$Tj@=>0?TW^m7f|1wV1!N zUa4TC_+Vb*79N<8fv-w#U<@Y$?TWpKyb)_2!QaHwUmdj5(D5()& zxpzEK9fd6X*q&8X!sGYse_fbZ;eZy^qK90u-BqN=kmOW38n39uJ%d{~f`uaQZlD1TQ-DBN1}Bkrq`22_=S(gCaPWO(=-aS}vLB5Ewwtp^qxR#3Z6SZ0 zl3G5LllRAbPhk$@Mb;yzht!fUmT_|?dUZ^S4+e|nDn8t?C=ejh*c=uLjjdL6z%SAL zKto+bscO&d$^HZeB&W7lgNy;D^sOYcOYLx!gmP(OP|D#rxF*L;O9zNx^Yb@nJfzB* zU$E^Z2xj;qamP?u{wqevN$h+kD7y_oB{LF-6)qpj@oP=qzAK8KV8`-bmd_m->zu#( z&QKecSU!GvI{#j>7F!>{j>R4mEwT`U%@R!#TrpBtoszR{YgS`AyRufcvyNcMvb3Kd zdHadhFF$Lass_$aXCV1D8O@MXiw(Ix6IGKk+fl0yD(b0ZRMi3|gp`O_zJ&QZfL`Q+ z0Dk!f6iMKETiU^)+KpDI`A|-XUe1S1T+gjD8o7A>%gU z3+%v{vE#%jiET10#a3yd)0>i7VaE*edlOR;F%HFUDMM8v+oBzwlHgs#q`6^adP{2k z^LL0bLCRlVuihrE(neVm2&A$Ki0bc$2(+zCu)k2jzEoO8k`sDHQK>&wq$u=vkfc(3 zM0hdOvmcg1bQe$24=3=@krG4PT!ns zo9J8p7Hf$8G8}LU@S!MB4&K9O$Ns6gm@FKmFiP1Td4{_vKL4exhK>r+jx0MT#OG8X z#|kxvm=0^JC{**Xy$p<>-dKtefr<>qf3+?kBnAY^8P3%92ly{@CFkk<7(WisrujVK z(}U-HdwLX%zWrAIFf5I=F-i=j0BR!p<>6B7XGTylEW?=i3WpAvg!R|-O8UWlV-9L= z+j6q`yIhzzGoft=2&6asaB*fA@%vQ-Qrd^6&SQ7&%KJk1>sT62J6gV01QQZj!@H|+ zkjlF%#Ykn@P7ECE1 zM`8}+YECg=uTlm3P$4}OA#0o?NU^a-8D2l>=bC&iP%w8jU>g_3(Z$6=D2#h7h+_=i z>g&QamitAIsH>jY8e^rsq@I+F1SdnGX9*xg@RlLPvbz0}ti0|f?=K>GqDZt7PmISN z(y;n14Lgf5BuT%eLhB6I!^AZmOqD-4q94`I>gJ>SIhtR8be;L?;-l+e z-TUY|rv!faSh)Ss<;RchU69C+f%WCtyN@2*<<*;yuCu)Uc-*;K=GeZI7NT#&2;48+ zD88M3!$7X*&chw>)<6g!N|A3-Y~&I<(Fgbxj;lC)Hba^1Me#*KaPC9{oYcq*KRY$s z|754n7p@3!F9vmLsspiOV*Wu~tcScu7+c$iSTsJ~aGrG0exZd&7K^I(#$wDnyi@nk zAO-b}7GsvMcPbQ+s?1KP_!TG4JvG3sz zIBwA5>m1*dqiIFv{^a(qxlp!pY>b>oi#d@Paa0D!o0f&gHWe15Ij>vSoa)MMa1?C% ztC`V(4uQFPO(s9-Bg$CEoIfQEwo&RX&CIY8NaM?cEeprkquLbpgi%(wk0j+_2vG8sC^UJIg94r_PC8K zk2*Wue`Ey1?_Apl37?XK7-amoL@P(nIE-q z(j=){Gkfd5u7%28vxL@s#HlhfjVuF+C$snZ;p=+C8{|!nZct`CIA`L1l$H2lXL%F| zP9Aa?T+0MPrsVN(zoBo{E%`8;1!34<-aIjtia8T%d*!&AJ-$6E<+?MY3LbB9D)JZ& z3&YH%HMA*C_?|;`WdM})Wn9&zDEp~@V8x5?S1Ki~jOi6mp-Tw47S_qik@1K-;kdyg zreuogrnt)BH-mOpXg3T^3Tq}li5xU6QDs*b*g1wp{1#+IBrNP z#NO#eU6|}6R1OCZ<_Ci4!HeaAnO_VyOQB~d1y$t1{OWt|WlU!ZN(axdUWOn)s@+@} zo^GKjP%jz_s-vdzKJs)snfrl8a>5w;W76B|ECsmG)H%!u5#SLds{;UT`5rn#l`J&2 zsc8L|(tLle$}gqm{&8zTyucFr!XR`eVS{zH@j*H>MXwwzb;T{~wIw+*a_5ow4IYYny1CaENWzPg3wfz~xz%*R(i*5LXNxH1GZ&cH zQ;Nmydh_`0=@E)Ma`Nj57LRaoQKUy{pv$*`eH{1IP{)ifD$onSExN*T>mG_#HW|2B zgq${(&wkBq^Y0YS+;iOY5ZCtGqqy472vlvqYp`qk4Aw|&9QzE(coezXGFu1LHa@kt z8zHIf!=3}tWC}u69I*n0saim4OA4e)nXKr)o#~2HIeD9MxGK$wM{5i85;Tx(*05M5 zMhRh*^X9FQ=4TitEji+d+wTCf8f*Zo&jzsi%q7t8wLn&80@({TPpK#&<9^5RaHQ7U z%47|g@MFAmOoKia8{E=60Ylawd^Bldi!DG znU!t!fC^0XY{hzA^;1Nhtg48al&kXinpKOU`Q70rv8H*A8)z%H*NM_`9O|Xhm6BZ) zH#txH)_y!G-j$Mh4FfOXwZ?`9eq9vx&~Iv6&ZDcp&B@b4!p~G8;g?&z-*!?1oUMp< z_2P{gS?za`Z|%!KLDfvn))c|d*Qc~3zmCY(=rdh&b$=&QK`So4pA#BQlg8_-nLo_+ z;W;M0xsD=w>TfTL)o;H{`!F6#EGfj$@AaSWg)mwn*Q?6emuD zL`}=FIE!-McRWii$d(#xZX0AYdoG~VWpQ77v|Dt0c%_@e_?1}pwGEBtD1A)nOC3l2|qSv02c;!@ta7bm@Rc8KaZt~4J|$eLr@FN@)9S#uza z(W6?h4QKu93m>E=59-r=DZtVLi?7SmSDacHDd$a%`qBJwd80UIzFGkEF`;Rj6v{Y4 zl>+T&T8`ys>jl2$-G&_mSu`?Ok>!vAFt1KmT*Nk9H$m6Bk3Hl-<+fw35#TBH^!_i&pewKDoX&Wih*Wni(pd60tt1`O7)|Fkb?v^8bnG2*#g_`B~l(QBn+m-Aj~?s~hiG8KuRhlpycYANl>E71!g#?9`N8N5P#z06G`0Bc5`Ot`TO8rGwW}hv>Sx@yEJAyUV-&XSIsJN; zHim;!xQtj9eK=xiT)V3$+$l(dWBJ;>02PdwnrJ~rCL+WA2PwYpZJB#EkX)Iny&9U- z$0dpePGcQsSEYL9r3!6b)0scnaAwwK(*Yz&`motyey`bKW^J~p)O4N9m2bnACyMkM zpU9tRzjrTbZ5O>#)4lYH^g5E97+RN!4w~Fy!%bFg(18&s;&D3XtHb4~xuF;ujZ5?z z9%t9a$12a^h{q**jgPZywvGW&~2c|riHGNG-#SQWGx30 z+fz7uXIKLanarrwc$SOIxXQRmoE;sdGgI-TM_&9xBnEf$bS{Y68@eKRW>9yoD zrBKF!+~&oC&T0joow5BN<>39PDIT&zQdu? z9Gs^!I73foaGajbup?=?dm-5(9A5%VWisTHVj2T?`i4nNVwl7fVi$Tts_8P?WH-v* z@}LumnUYuX_X)q7J*lkbQ@N?st1p=u*_=p@VPy_+B{{%iBo>VGb7G!h>Q)r z8PDOx#e?~AjSgTfMB!*5lFDc~iNmhG3n$hmMX<9G)X(U6Th)E}YaViDZSI90^kGj~ zqeXXQYKtsHyaCO2#~*dlD#lNx#^w6xPnrD`m4TaOD2e!~RC`m|Sx1c`@kD+F9#SF{ zIA3Emmw?OT1LD#WYVA>gkfpQqO?)$j3oAoQZBRaK71ssY7E+dOPjC!7@(VadK2;Mh zjnXJ@lf1)s4&5XQ5*vkcuUbIO)*Jh#0jOKY#p;@`mH5IpttrJ6Tg&BqLNKL&#p=#( z)tM*BNhJ;mNqmxUVC###2+ks-kRh;q^fE5&}Q z%3ggTkE=%E-O^;Bbz1^=4=3|#{=MR-$mktc!*C9vJxlFVnmPgj#59hBaX6ri#`eai zbicJ~yKH2s#~wkT3gO5#mu_7W6xUxu$i zB+T)R(unJwMS;X&y8MP^umC{={LqFnwmB>c5()=7oaK!&?sCG5zVyih2x=`(p_bw| zNZXV{op>v%YMG;Zk5MP=cWq`kf!6}sHLFfLFKRTEm1i4AKXe*3XVW<`O5~6ZCCzd>gJmM3bo{!1MDQH0491j=ulk(JR@6i~HPvIMPGwqgm;jeY`a-?nar(5;Np zbX~Id{1B--dNE7z= zr1h1yKXj^L4T!JT7YY&`i!1&2&dK~Di|)Bf+>%@ZUoNX-6f_8%m)5>sh4BBH_APdIK;a4Lgl zKu2q6w_M^xQjC+H5R`I0&I|pV%;Gv+VG-mJzb;dwksE`O=s698d^!iltow;Uz#mw6 zGuBbLtO(9IY1gRzSd1Gj_8=*2PM z3lRKGF72=q@W>{mUBHeSxGiOO%C&p=SFKZ1n+r+0r7l$amR#ugExAzPTXH!B+>*=o zzaoUeQk(=VjDs zaVRnXIEmHU#2GkRg|s203(K|d>?pCd&k;erenK3Xlj*7!59*HD9OCAP^?mM=a}SnI z%=<}NTBwnZ4gIG;z3^m?>eP2Ztzh%1T-=gF?y%hEQ@QQCp_boEXiKz>WT8w`xipBy z6QVxmFmz?w{^Iuo?%HT>GbNvAl`t^5>mIVNp5;cJ3y3N zpJO;TUD~qP(D((!!=|A^8+4zIo8}{Ia8bn2GSnm!IW9vFdbc`v1*$nJn`4N|z`D`l6UUI{@k5Nrx*+5U5O& zxgHn8{_mgjf_p7z8_;%05y}jA>X(L{!oukFR4Y494K)E?n<DtUH3=wfKu~ zRP!>bmne^++NZpy>ief!mKRF^qO$?NU0?248Q_75plvYuT?-S3sXWDmH+XzvH>3p% zdR9}Sh#&c3Bv!&S)J6m&;q}E~?-MP!W>I_^2p}rvNlk8( z{(`M>HoG(rxS(|0_<>ntrD-~3UoS4KvkB!*+?TntTQxe{`}gk%4Yh(?5?R?s#$e;C z%=3GJypp_MTyP^&%iSQqJ_pEeB`Weqi5B_QcX)AnFgcDuNl;SN zdgzw}GP(5BFpqSOEKZX?FAGVO0+(wvJ;Q;6&`AVQc`Vtuv?u1vx%t}Hz6*Wpn=RuV zZWEgvoG^!5=cQ7}UK^A`8q3MnaqP`qM&wwQnG=vuCmc~eP=e!GLQEBq5)D!Y8zrEh z=qI2qVXu~a%p0JSJ^fPC5MB!`)d+92JdwDoaQ!Q3ry)pzG*+oAqVczj649qb!`yu>5@#*1s|e2QvWbZ+hb=b9VfxBo z->e0K^4Ul^mj0BL$)?IoeM;lm`*u}heJtJhOY?am9>uLtsr5WEZvRW1Y2Z3IdidPh z9H*-36g1^!AarV+24xp=t+@9){LZS?Los%gE-PAN?YBB>zUyUC|#;3f0`&U!yc z4veMu{H>l7CDd8|Zl@mx&72aS%2iVcOjVNXCG;7d-FXV=xe_BL<*cS+@SfsVi~H21 z5X!TH6V#eb4WSO0GpH9CNSD(Y(Cg`pd)jQRKsZc>QA7)c z#1INILhFTADhe1MsF^Oz3@eM2WpxB@H?)+d>CGjfi3}5%hUwmkM5)OfH3ke!3uSK2 z7KyKsu`N?a>Ui3hlj{e^twn=9ZdA^0_B5`QWu^@r)E-1?qxQ@kwn2MH4I8xw4cw@l z8|%Q222@7(es1^_z#r^0qE*T&UZqysro+S+7h-X&RA}&D;9<>UKo^)AT}KKHb5Hsg z#Jre+`Jr1RY^S_WH4LafE7{okfKxx=tH66AAYRO!n1F0>>U(#kP>5?xIf0l@MXQn# zC&X^Mq&Ny|6n8r`uZMQc$EX!d4R?I|*;wb;){UvI1>Xu={PG>UBb|2jY06b_pL4c9 zmElexeCqm@Wq3-TZq<{G#ryX`4li~#h3Y;Z+n=#%4 zGs{N6IrUQgIXXzGQDu{S(St;zHpB07^`cj+q?Wj{s@$0^)$$BkiuS(9L^dpTI*qN# zWP7jAbQ~NFUeoG1jU$f4Jd}lCF_@iFC0|S>^H`;}FZbb~72xq6Mv3w- zu}uVZi%~y7T7Op_%3x@{IYB#W?-k~{W`lv~P}?8>rw=wNNC3VKnpR0W)()Jdlx{q4 zBHcGZ9jD4Vxs5qirpLA`&Q1bbFGs{7YA`?SN@V?!{gTrJy^&onP5{lS&uQX zYSMT5fthc4l9vzSX83OwT|cCKQ+SbqT15~j{g%qcWcVjUtLR8&tLzg~&xJbFDUj1| zIVhT5jv87avxab^6PGQNg-kYo+2s>}e-Ut=~vr z`+Av{%VK37F|=5x+X0|LjZ#FPPEK!~sftO_F`TfagW2u;EKSG8n0?}koRLOp3}p-s zYXOQT46xsJbGgAkgID5W??as#_N(-0N>aVxyjRvNl^!)E1J{QzWS>F%R|8aX3y#PB zLa}Lje@pWT)g>!8WAjWHT*J*m%21FB9 zjR5tht4#U(fV<7CEwv{Y3Ko{?6l++vl^L;a2Ru~aUg5r=eT9H!fm62t!ivyv>b@#G zET_(>ft2OI9@o@C>$E24uyG)@b<9H_JKe5WYjaCMZ65=_)Fw@3>=V&VzeR~m%Yz+) zM}}V<%jEWGp(5cXi%Zm;8{J67&`S4U^#vWJ0Ioq9mS~W|b{wR9VWP@6S67#AN68zs zV$b8$6H*!a=@p^7cpIi*B?co2|JGK|Z4vl{BG-L|)c_c9LHILMrWsKW)V10VPnVMO zYZy7)jjx;^TiukBmdnLb&`W%EGYCU+A!?NEZpe@3Z>~=?gC=b4AZ>pUJVxDlo`e(R z3dn09wvE*DTynR?oKDqobkt(ja&G25rB)Fd9T&-RfA{mnOdN#IPT%MBjpbOmxCINl zGJ~7nI`^SnUm{?(8cbHFT{-h|k0Yb7(`vPe?LwiUzy(teJNqMdJ|rKH+4~f|!oqE3 z32ROvS@R}zs5v$4ygHXLlJh(7;fZSk|MOXxyDq+yHC0S}FD?xiu`#-_0?~EED(ZtZ zbg$|i?^|A7x;(pKl^d+KmMqUVA-U4HqqD^f9!+a`!+@JDJzoTxRPVy|S<;w<&L;~+ z%MrIdluog^G@6_gyAO9Hl*lCzXv9OcLf&XJQUths-mgrpt!(=uS}!#wO9uXKRJJj; zMfuXC!Kq5@d0oO|n3U_ETKga(PGM4KT+R=|ezpz!0dxG>{2WPe&{o+e$N23>mIB^1tkw{7Y0FxTxVtzRwR7+U4HI)cf9eRvO>DY<1^4omo6 z5~%7EW2FqyCi}S9=G2J2B{dfa#FO+#eHIAXtl4H4XesL8Cq)iKFbcS2Y zS14xjVfUI>-mSc)%-*FUCJE|6?3&oy1-C7~dU#&`p=k3ed zrW^0&%O9dOB~D}#e598eqG_U0Tw==(BR9Q*USC*n<3Ofpr%f^d9-khzpp8m>i=!q@ zOxg_52sqwWQYCwF}A02)9ZYKT6W(K3g2sSB^3xHwO3fF6T!N zc(dSoMcgCZ(Zrd|rkF(w%c;Bt+w_@fgc5#m2-Fi#+GD&g(>TdadPBjPqsKs$=Da#c z;Se%N;qWm?;enjH3uDY{eZdGICd3SF)W7TJNSk5>{xRmL$0^Dl4eDUAjm++3kuF+)AK4Dz_5OnEIRcoc%2f`jT1 zC6|BZQ7CeaogxTjfUk7>4Gm%W1V7vwnD=rthuARMKc?(#zx_;;7{(4QRtt4!fKN@~ z(&9p~UBgvOO(ToX2yr~nCA2$qx`bOt3u!hEmnQRdM45>xbik>Isp*nzrtM^M_H7!o z5Ln$w6xrtL3Qg6izcyU@55Zbx-@>&@x{b@a=_T0#36fyo>1X@7$?6qk;1b1Wlcz(xydG zRBT$*O&tw92%L>R#55po)|k$Ns7?}hjTGy~+B`RnOt%?kk~NvPjdaTbb!9}3a>)%K z_*0>o6GsxhYW=bkJX=#^DjuDCz=;ikPw+9F2pnf@%IegayK7#kfb6NUzxR zWqq7n=_?B%?fvMoxYDAo{q|we!BX*`ZtuA%n{>ds{!qOwH>Z6U)L3=s5aNSq^?@$$ zS^foBVn5;(5*|5^dyUL;xviwls6aC=6xqeNze4e~}XTc4jz+yZa;bE$j?d#d>kK)XP7j*nOSuUKL0HHQH|Y8;K+)G;uWXP6|2Qn$J4_$Bt*o9j=@<- z|KX}mfO6OnOETF|56sEqW3FJTdG8)`UeJLclJB1%pjJVTe0GCzqWQ8=7ll0;Pkez@ zz$9ct=2T9pAw&w=Z&Tbn)uzz=po|-<+A?2m3dR5uPySq;p3mAZ$Si}0xjy{uU%(WK4ieEB?^Spg}6X7NUFsnjhqHKXPe^5 zesI!X5q`CL4etZ7>%r9|z zZhi@bX${G6zR_WO;*y}MWMDp(jMn7IS}!mdADQ9kMQ7=ku1g1MQ<%^^GatPVQi>Tg zsGdsUgD@Sj%PC1A$tvrFqnE^7LgD7xY!yp3o<>oxDgdG$LC_cQ{Fl;@fnCm5a`{kB zP4-{O`qduO6~2$c+Wc%|e5B1^6&J0lMwm?77w(O;KNw&%KH{dRqZdot2O<_nbe3p-%Pg zp{&DL+QeX0>gO(Ww!xtGA^5hKqeQ_YX662D5*(6&H=|I)0BVo|44RZO((rYOc1yBj zTc)Z-`QS8!VGB64pS06{0v9Z%>D#UPiu(gyXqM$JgJh4JH>Z_&vniUn$7D2Bw(YNo zcazy=F(poBB7OBsEh~(wyQo`c^9k=Lc$9~vN-{Q{ zdEb@$R|Lbbk##U(kM%c{Fj0HFq9(XH3Mlc#$L+F|L3fi){;6g)(OPeM{hR$_zwT7; z_~-QW^$M+v$tBnWIBY|!Jfo#86KU>?v}-<^F0A{dNZ+|h`klB#TIGMDEF_2zUIb(a zA1rgM<8nkG8jP->p86A^?aim33(*|&5!QL)S_2e!BGp+_AqV9^VVndm(et&p0ey}= zM8dJ%w}7UY5Fg6E>KDW8VgbV2dYywg!&>8d&dgy5K6&-bw0hq?u2jHM2R`MN>M~wA zfdf7*1J=F$pG6xj&}>*Qe!Ls7lI9p{*MxpWf)zbQ6Fn-`s&qhxI-Nwt zK}v7RRtA1HC<6pW7EytK_PKq!NXe^i>;q0d{Sr<;gC_u3Zo)m(a0vk#v7&4)X+3zW7J4IMCvZ0dR6>Fhs$y5 zE<|Ri__fL)_2g+u*i%w*WC(cT!@_$QhAG3@_->C$hh=mjkQ@tbc(gn^!6C`(jpkic2;^fO%*rSHxTA zlde+yIfk@a(Ov9nyx zZn|%0rxt<_*_Xj0x`!w4>TCHtg!?4;%7^!sRvOd3GyF0bn*#}nQC9r%cUV&uQUM_W zWy=Z6*}D&APfO(T>fnKs>`A(HrsQnZ%r%SI*`%JM9c2fWG_`9@`TN+WEVY7>2#het z7;xm_C0(k|#ue8lmEessqies@W4Q_)#2KlXJ+B{~E#BaplkZ%=n$Kf~?VT+R$7`{R zW1lF^53Bjhd{v%Q1kiR}TyxV9JFoeE_`YCVb_=Ygqc<$?blX4;xGONlon*Cf1WR?- zJ&}#=!HtFTm6FPykvNyjIZGWx(vj4Ianyx+eUWqH+OS1Skue+m_n;k`Mud?OK{1kJ z?nSnfLd@L}@xT+!k>~m1dmHcHQE=ZqMP;=;i56ggj=jn`d*>t!z&MSCbQMG((a_BJ zI+McNS6(*k9$_!JzB?NNR#xh%hilv+1jTheUZ-()dvpM$!w;)7`_BAu0im>U@<^He zRyz9$d%UObqmVy)hU*%!vb@Cp!sH#R71XV43`=~b>wFx)SfdqAD)t_nJ*w7>)xPD` zat8Fky>Op=i$z?k5@ZKi$aQQL%%QzW0&}zG3fU;0!5RTr#{Hv zyg!momDQyc3Otu#RlAl2C>@8c#NY~3lV~xGFdbBv7!P_)E?S#6`ge$r( z5)UFO(@H&7+!MKlg&&~Te{HYQISe4-r)JC2iaI{mxOvVe4OUi81NAZ*f(bifN7j|h z?&ZURs~L{$FCK95bw2Y^Lqvn_0-C%Qv4b8hwu}@ByavV_m4;8qRcxES$+bEN0bISg zSo_kThepN_#7#nc}zeH+9*T zS|R9H9)Q`Zq_xyU5hQI(+*#dR9BM&Q^_lUb_jx=O5rVBuXw^oz;&l*3QPu5669{_j z_VvYOWC?x|v^rY^1S;%DQEdP%w0Q-(OOl43;*(GjY?hJkCUV6$W1_(v)Q3n4?BSg% zgyJ3XLEf`SMW-hgPfId{P1dxEoKv*NI97Brxmw19#gS8hA}t{nGNP5DQg0tF|<)VZDkjhcK z-Fn}}ylWM!C!u|^O2?Wd)WC%SOGTOxbbL3&sZM85!DOcU+=sT}wm1)Ug_O%WCO5-l zwP4&UfMf4^Gl?e*vyFN&iNVwt5H?Xdhi2xqW`NZX&d}gA!PryAPnFjzU zPXySygy7Z8SYu;ul7VvV{4N2T;Vs8&Anxqe)EM34)!~fSWD2FwG1I9XM?D#aAvqjg z&j{9QW6@&PJ8I?2)>wTKCEnCbeEatFYF=*~NpQPo zrS&VK$MNefffcVzYSR8N_Ufe+jO6kS5c4j~fih+(H<=I^1QTe2u8KPYbDCB(EJ8!RNwxR_JK3?e5nZr`u8*Q7tbpkdDPtd2i)#WB_2U-1+4kqgt|l3Nr2 zd4y~!#8B3YZNz?t=fP2>bkKVuc6HQ1rX5yT42Nagv7Bl*|F#jeGX-L8SEyTx5MZ>R^dFtMH0Rl2uM2QuR-5& zZJD2_3Iu6hymtk`+xgk0uDG7h-hX>~gc>xe6+C7lR?-v?yt8?I#m;dE`HJ{#RyXHw z7H2C1@T%j^Du^FLZ41jh32-8ZkbvU51n#&NN+6?UPV1t&EZ*+ck|SEPrc6gGWlyR_ z!;0LRO%?81mi7$Q7Ro9PV+4W_2C=K>T&vCm6?6^|SucmUN89Z)#D@B-4uli~WY5?@ zB|D$L;ZD0bkOSHaxr+1mxPyb3lH=G}o;C>8Qan0E0pZJtt|w;X>&-4k!_3rx3BTgL zpe+pwmTMla4{d<-po}5xJJg`3c9s^H^b#JZL_Jse00S$QLy>HF zag|?@X$uChjOyB|n8qJVDQIJ7Y?^UC3;hov7CIq&N%sb#c?@ptNyIvWjqykpXyJda zI4!Tb?>cQ2F=eALx!8tx*0&(Wunc?W7vG&O7Z-Mw2(Tc##{t>)4a2XWocG;Js)EnI zL0CVgvemvjU0kDeh=iFmC-W7$rBl;TqA$6^*mGf6?QqD;#?|#fJK~s47-z_wICnXRn2cG-1-YEnAz4|P_qq8@%MIv9A&Cc$rk6#b*@gXGXGr+bLyGKW1@Df zZdszcg-Tlcq5^3AOi~J(D5A`3s)!*n`OG4oT(?A_X6ylh1(7Pr2~^>-N$%Lqe%+dF zY_QZISrpVc_32E{(IJC_P~orw_S`9(EoW)U8?A_}g0Zp*5|vf*dffa1+M&xe+Q{Nz z>q~wvf!FrCkt{wQSJLrInJh)XieTn+&GGV~X;uUuQC_JBj&&R}C*WIp#0g{Vp2F#H zZJvCJ*JmO#o8D%Y*W+@{l8Tl{?a6Er1E9kADw>v2&N38@>w1PR$hhGS>TBYv7naSB zlOne$HT~4UCe%}WCV-`EtV7)j+53DJf6B3V{XFi06t_+DOQ9dozH%ZUJpDZ(A>xz< z3rR+2adyq-e%~R|^iBc|#akhwn1(%My!8Xx!XaWU)Nw;d23!<9(P_NGWcWfSsSwjqV#&^U+`f`Nq_2QUNCQ#rccF)QQbH+giF1Lqe=E05r6;dHV+j%i2 z32<3HGgNchSdXz=i9GctidIkzGKg$?bBZT)M-hrG9w<7J@by+269l;#M?L7G6ez|` zod!OZ%etDZvS|(eT&52sv^T|!Uiq1s)fUe6d>2a@7RK0AdiJw{gxwlR3Bh4sh3MJQ zo9GTpcnoqtEK{74v|{^287++EWtzo-Azhgcll45O8tNKr3lkXfHY*ii+J*6+-pYKp zK4-T@pvYTRgh%>B#lR?urlO-pn2d1f3?`I6;sx#-S0L%O5{kpT41C?$u^{%0pqfD3 zMO(1)T%o&E5BQi79FCJNr&N{~XusXEe;Gpi#y4_Hcz}p`5Xc4&YTcx~>EtUns)lb2 zV{v?p2n3*eW|{<)jtFR)}}a@9j%~jMwuVFyBjoe#vpE4ER0NS6}v-kf3tr+ z;-34%(l$FG(h5)Z%C@w5RXr(tIZ##_0eoB%ZEl}8H_tKJlmh(=<$iq}n-eU)93{~6 zOMkTQTBd|Cd>}n&fV4DO!Z)-77gsydNa*-02184l1w@$>saY>CeQ*`xXPBxo>XBVA zvV&wE(~RHH^a>%66=`_QsXNPu1YyD;8*g-elERjAk6lmcAR6@~@Te*YGToMW$F){6 zzS&%GfU&>k+mE&E9P3H1f@Q30%`zXqpWzO~5x~2*ZrbL$VH2JZ)p80uDWi3a2L~IO zsK6UY+`Rh+Wn9b@Yo2>qDNQEPH_}$!pls#^F*dMtO&mnTS4|mi9IlaGv7P8_zv@Kx z%z)$qboas(c$J5R$dt(3kj)ICFP@JgM}uUv7`ThJ&T!*~1<7+~F1Ytq2(n2AwN$qw z-RLuT;wkWqo^h0j6I1GL9b0X~gif6I=uF8-!vo#yF2dj9OwZ6u;{jAm5y1k?m$pvT zDJCQbYZi+Wr}yW2wL~#$cP>vQ9qDZa@xFjM3jDJ?s;)X&6Rd8EnmH!x|M?;&5xFuB z#6I1@SBKLvo(wLdjzk*`ULC9b79zh^Q%j z|3N4&h4`qZA_v%);DoUwEPr{P7P84ykK8CDZ7Q~ia}X|2y+k>8Gzq;LA=j?UE_f8n z8zXMWMZsP}(LGmlyPsYZ#w`h(CPG9%RS-bf=q36`5qQRV0(9^PGa*JyV#i~!diMe) zeWwFCFB>duZDL_CQRA>S^#PBNKI@FQ$VO}9&>sC17Bwivis_Iow?3;p$WG)xNSo0BO4-S!{Kd!vF^)vt~1D_hp!Qo18inai~z5LPq z`lHIvR~H{u9$Da{%AX<&ea!g(=Nz18BR8(8qa0$0e-}tyOd1Tm8 z2hTB?ijjGkSL1G??<@b#qh>VY!!X+K4Jkk%vWAqK7;jK)@r0I%5;5*@z7~sx(?%;X z11#MUn0$~;SZce&!s(9kg1>utUPEAf z2)wd8q~yaGHB?>a_VEw$8xbM|=V1#t1iRj+-*9S!`l)?t(a+O3*7Wgw@k|;)AQ4r3 z^AGAT;(IWKd|d~vaagwd_58~=dmDaz(2AGJ$$qe4O#g%B+yZm7K{-3M41rH*T`UMj z@A{MS3{M-(#9eZ0k6iYe9|kh9+@g`sukDgblVN+$%>l1X&xiMrd*2Ipeb;2hV~>)M zTFs*U%Y5B-GrH+pv1`-SPcI?%*Q%FTC{|XLE7lb!8B;RA8q8;9klEP&J+yMnIR|g? zn4LL9lD`<^^5a9j{_0yXuKjlYHzDWd<+B^E>}$)K!;#!mdZjG&^(8lX7;Zl+N88*5 zoG##Voo;`$w!Pl%Bgf{A^Oe%Gh2?&Jy#gB`?RC|p*GkCR2}b<8uqo+S;{20t=0Y2j z5Y}dt^;=id*-qvPDSA{rGxDt4aQDm_+_)`68KjR!GRW@_#F?2Nhs1L2yoZsHH=uc( z3^*w^H?y~J+3vEP7s9J1B4L>-6a+OhII?a00vNuAp-YK_(7}WGfv$OSOXk21+O>d! zpDR0}*^V>h2#PbZ-9#+SX00c--Ix2w8RMEwCf<-zl4C;|HSrW3^K|{pxutSWiW7cJ z%$_Le9O`9l*kYHu4fk+yd4q8s-^Fs=F9-4!tR78mx##T41ta+O)1M9C$@=fn`T_F8 z#f2>DPwTS?u@96QY$!78V+!GMC-WFHgEM-K#-w=q1l|^nQO%v|vxEp=sHqMxM`Fi3oJK?dWb_1q0B^v0hDUmC% zCOZ~pO>TeU>t-aL*1R!&fk*QZhHSO&;=A^RfBwSz2&r%^6 z`jtI7siDTSmkD&w+MPBdR}HK>PA>k#uO|bhV>%CAetdzBt0%Zq>U2_m?OqhUpHybe z8`){ra))m&1ccGkANDJnhE@MtM>CUP-(dZbESrec;7*zwn$lCDm z6?QyM0_`bdoLe^YILmi?rrTY(HO*z-sIkoOrb5ar*wBt_m{*z_W_VMaO6|rrS7A@D z_RMj(ZEYgEG&qqrXmh`Hp`C2DS7O|9FS|4@h8=`z&}fs>Hr6D2BRK{uAxsdKsmeUTVxye7bsVnKOUY zO^3|fBm~8T)TVi$koCqY{A$MCU=tsCB=zPHVOB8^D)ox};{vAh{gP?aUbciPD->&j zwD>3}yvDb)vv+0$aeoLDH?6}Hrbrn!%zx!^S#3P!!fY7OAA$Wee^!a8}esE;-dl8I>ow$=f_I6ElhSz&g^}YWBxv3O~vOk z74yXkP*%*0PeLOmL4fI?o7#;r8(p>Tl@Oda_*t4d_8&e zDspsM7DKGHM8)W(cH_4m(NC;>=ds+Dlm8goGsIWB)ujD$G5NmZEpIyl;WZC8ngGS7 zxH1YR?P;Ai^sxV)={E8SHo?F4L*<9)xhANg}IhkA`ZIC}27 znz#PV#zY_xt9`HW(QR)v8YHw2A(A%eHX*r&4tF2g-xl~Y4+y7ZyEqVoX< zbKNFHv8& zwr_h^vE&w{Wm|*N{WlfIrP}utOKzCxMQmrM7r8Bp^HejIsdp4hGl3^nI4NV3lR?ZT z3KeR$KF7Aou%6?&P}%RKmV8dy_07aK)iuE-B}m^M)`}9BAv&KGNHF5=*15 zM%@5@&OJ6Li16TaIp0Q%aTY#gr+q}1Ti!$rRPtlBbWegPaB_%5Zm7*-NI9d1E9W9! zO{GbxVk%Wvc^P5rUJf19*ty4aEiFy&?ZXWUW|6gxy1FZi74Srt>Ja5trJ);;0 z!~pm3U5*^>hC?gGKJwL!kL;$t_mCCc(_iSAszB578?{FG=9Vxd$!#D0Zy9OcZJ37j zKBX&k6)7c=+T2e!Y^Aqig{;+fa~6KJK@ze#Ru}37(=0*LOCqGR9K~-?A)bE_afnNv zJt6kWw-e_W>1f*Xq5ywXKgD z)4;@3TiIsO@s+$EE-KZx7J7evGN)&_zU^K~!h zvL=&>NZsg$bb~&IuGOoJCWM;I*H;!fS8MAI)bY2<7iB)X&-Pk3NJqbJGSL*9(z}YU z%k?91#Lmw#x8P7@`E?_^H!Z*29PV+rDpIg3Lacl-HYAcDW>A4M4}* zBzjD#CL!ij6jx1_U6UQu&(Sx9wxW|=qB5LM`QrIsaVAVk2U zDG1FnUI8`go8=-qrOZc%E`xs2D5HDPYPc7hEw+XJ>X5<;9CpLO0WQpgR-wkp?Z)C69R>f z(xKMx(BAa;Zcc9?B8^C3IY5}SD4jopW<|Q)N@p|;a|Z}8$ui0Ik1queaj(6#>&#e^Z9AQG6Xj!Fzm$vAAKw71>p8&6;+BO!8A2M@ z7q1izC-!54^?}9FA?jFR7$Ox-K_FzokH$&Kh}zQDY_EQH)YP}6s7-IxX#Q#*VW$#l z>e8hwzq@Clx5^?FM**|Mq4q$Ayo8o5g)*0y9?`g2i69LTQ6WVUk)fv0x<0aa-o_nV zkV~2{NUmEk>%)1@ace7|m2WhINEm1@6&X?+f5|LX`!lWQSf zR0*7JH#oIv)^J@c!59LtrC@yL5x|MvuHGDwc#qOSR`B{&jjGJ?h&!N)q0=OSm<{!8 zW}62RG$wD6Gg!UK<0}^LVp!5qTw6DO#sCZTs)geYpdSRHST0d~rYuXc9mF(Dod)f(}KQURHm?6D?L0H@m$2Bmln5=vvR#QXkEmn`pb1ksj_V|IX>y5|MJ04KD+z#pYJ?=@aXFYcOU;fHj&&^>gjv>j6P1?;^aO~ zy*rtDZ!-1s$J)BHEnoONfrXEkGZb=C;2IbZ? zgtw+ayfqEut!W@{O+$HW8q8bMaNe2*^wu<_x28e8H4W>nX<%$>hm_l!h|l*ExZ5+lhXrIBq#RxDBc(w8kIp(WX7W7&!*#mbFbXT%wbQFU7U*jo)i<`$q%Z0xoU>BzP^}D{${a3#33VkN`Ds4ak5Cv_K5Bc=wM6 zQ1Nbo_xr82_c{BVIi#pBTS*;9oc+1>+H0@9*4k@-94q2Z^Rb_ns`$!Yyahf67VB6- zUlY&(o$zW8zCa+a&AN9$T1bJ9$m^+{BR!IN?N@ZGUE$r9*;FQ>H> z>&K;v>T7mw)0&;sH#~YH1{=QtSS&!7!WBcR@te4DEI{{`v;;sPTe zBDOMvt&L8K*&?e>L_G71*Y||YjkJiC@qy@ck z{Yr(t)T!_7FD_)%m4z7IcJl4cOg5ZY+$KaE3%g~0fcdc=$%$vjl3A2G8T#T~?csHJu zgcH7d3C&CUbX=an=Y|aZZG5@+*uf?82KomRbo8J;@4v_hC(&~-fha=>{TUvx+tWt; z(9hyqQ!vhO@EwY24qL*d3ZiPwC+*JDdykue@3onUH7wLq+5|W=hqv2zt zwgYaKDgK-;(7G^zj>XI|MT|aGAl{;N?rHX>)NsN5%lS1bZvyG`8C( zV4IDe2rgNMFd}1t{b6^S1pQI!2QtXfpE4_~Z#&J-VO*WR&(?L02HS0US#VU35(nZA zG8{)kbWkNIZg645AyLu9L>WuJ1HnT+RNe6IY4Yex;g>EUVr5L_zMOM=*mBspz*ZTq za>~^yLqR)PJg4^za6-O(}Vd0p|N*Z7(o(=WtoW(J3+U(YV z6=lF}G4#zQxryZB;YjHBBkit@m{cvOiKR}=1XUd50ABEqSLt8pMJDSsiq~T@@pSGF ze7FOjCV&_Yo;H+Ye*lar!p}80f=a}yFfU9m4v0&e*=CNC)Y98{+W`%MqtA0Xq+wdM zPh|oQu;9^KkxF5v5xSaD`6LxJ{vf^=DR&?_g6D&$bS(qGQGuHtn3B%7V9v`3o)6YX zQr(?&4VfIy#{xeBM<=tK&!G`glmk@iMYKGF2O;nxx8v60m0BNC=I}|D(AkUaeev1G zeb0eshAiO*Fs$Z)68*j~87Hho281b|Uzy0-wtVP8*sudQ#R`U|*r!X{9V`)d;`2E6 z11X6N=g0Ayk<)43tfj>DvO&W@TX|sJLz(&!$(Qk|SZ#zma*4YM0dKOY_{S!Ly$8;E zxvwk|Q?Rmw;AUl{fSuxC7!Ev!$@988am$GoB5vmq^r8ayzae2;a#wai^RONzo_t+~ z=cr^Vf_WiyLU?8riz7^ad|SfXG{*Iz_^0z62ViE|6DTUOa3}GIW=dKQCpfCqN*T`1Dw|FI7zgCgh z1dqCi+Y%zB56(P%Ru~u9!kg&JulzhaNYQl(8$_2d8C_NIAod19P&KB#207MwaWDsb zQ;?1aX25N6#;b;f(P`|6styYYL#e~>5QQmme>DgdY|KFL;{%96)CAv?jImOmy(Ktm zy#%DOwUClgCDV@ZQkKjEe92DtD?n{_o{S!*SP5+>i0*V$ArL9UAt+Jd4eSg%u0sk8 z8SJOX3$iK_#`Pjx#DWO$ax%S&F`uy|4W|Qn2o{oa8N1;5QLa=UP>6W_TPXs6o^GP$HQR`H%0ZF2aiX(jW`YR(O&6} zeD)F=N^JqPZCC_n6EQ%#_kx1lHsZ>`etv-pDz5bsh-~i>@H8HUnFfaxbz`z zLKM)wTxK;krgnUah>Qy@g{fot zFdQm!97j;3rWXdmM7!%VKKRTmAD7m@A$Y77X60(|XjGQE+2_``!TX&dqPRVQV>tN2 z2S$*0hpN>uFQ_KUXH*n;AmLh6ywL*E0W@5--?fywp@#k%zNkvF(?D}ONa0L8Lzdnag!b|Drs_Iv4J_rkqPLb1}=+Pe-W zb2zJcs0JcMzg9A)$G&aR5DcXX7>haKkwIQlF+$9=QDQ8h}l~8#t=K_!UZ5inc{CkF6(7 zC!?p-q;YGvx;7!_`|K@O1f6Ek_m1T*Ahe#Ju8RW6kqn&uo(5Oe7_s__Xby_W5ZM#xqx2Gn}D{SkXMKvO9z&UY6XGNHATN5JT(w-dh4|4+<5GKVow89K7)<_I{dc@0USyaHF!}n6$E8W5P zRbbZPwAE{2RiOdORV}gbiOPV4t{OOwpIB_oP>!-6i1D%=1bIU~Ob6fdAtRRyVTDIF z-~fb09?b}bQ+g4U4@{~8-h<;sBprN%qXrSUC$7%qr{UBMD!SDd9vb7t!zfhn6Q^NV zTERj1p?gj-$8$03JbpjP#~CWmRLYn2AYITf0Rsw+bbQ+@NamNc!;h;5i^Bu}R5t)1 z89-CHCWV60|>G(omv|wrMzhc zMUkJ5o8;C=rw=Kt3%cr~E@2XS0!l#|!r{|%NV+d=Req3HNiJ6BVg0jv8*XvvIg=%J#w&f?dJ-{ipAGnlFz#t+pPLUZNoNA zoGv!WTGa}h(v4&3>==g~1TTj~7WsJSvQkoWj=KEdFymi=Z4PCs1{+tya&Zd26gBXy zf_-t0j^?r2Rc!wWQNbUy`#^!Qad3((2CNyT3jz40VD8!Kk?&q>zw|*mX;5X71c|FP zZERJpA0RZv#Ilfe0Kt{40^fmSeT9SX21I8Jg}#0615T1)9%%B|Rd5X)d*}!`%&|R8 zhajD6R+1LSjf7a!RlKu1Rl4Xoh;<9X*&94s*}Aeh~g z5}(CanPvg0EZ_F(Ll_?x!+)2NQen-tZ%CWcQrB6ej-ehuV?;Qnt<$UlbpGYP$M9bc z|Cy~h6UD%lFhefHvMhZLt>po$C=ghi|IMIpOsgSmQf9zGXN{MDC3{jvsjAdEig+I1 zyPQIeFG`Bp=O8h!VpCn3`(<7Md1md)(kFb;5R`opu%;Q>ebnr?CD^{J<$i} zQhy5nMaTSf3nu*b4RL_+FHp&q_(YL;5ixvM0e|NZ2iNU8i@Fud0nZ|&BcfdSnmHx4 zOX#KGDBMms3eBunoWr={HH$uwL(FP?l?=T#og-+kW+nj*J#8Ch%j>@;Fi9`=+pIl{ z5Wc^}dK(F678E4^UqZc_G2K3<>@ne)wa)-DTLZ+cBcMKeIxQTEZ_U`=nAHQO&-8=i z`cRJaV~AhbBNz7JciN`SBL59x%iT)F`LJv9DAqz zIDudEu`9|QfU`B6X?>tcIM$|@;}qwepof?xEDKD#o<(1YeVF$GTARV>n4K@9#6|Ry zGvp%5T|zk0$}U%eoJuNF{uJY-o{Zwn-Yv?p9c-PPW;zLT8fD+WujxDqoZKuk>q!wx z9+euV^Bnq$Z>pmn%I@NP`ZmVqOwje^@xw!mfjaiqV9QiO8XaK9SGmr!2< z)O&!qk@NWyMm&e!Ff?dPc?=X+ZA$r>14m8Z?>J^U=N;v26>#dXwF2X+EZxNa_y-( z;I6ttQ_1r=b5v$&XhD1tY2QFO%H%3|hB3-QCtozpRL`PSVv#eu(SpKaFYyV+M5w!w zs!}T_)X;L2EIG86LtBJ44mwf;jU$E9BgCuEq;`*B2IY}Eg}*wRI2UBz%BU2>eKaF_5$QRLuR%8?Q$?^8;cf(Elulza4qz$s?nUi z;pOy(8aqrSq$(tgSx;R^4yVoaI}(2b82RxDKfkjNv<`BGPFxXC`{G(Ze)0KENYqd_ znl|an3Q{1ZcVS=P(~N*;R=_Uk9D~dr0jC}?2aS1*vm>tgV^-s1FQUEYP_71wQ3Hi@ zQnf#{DB2)(3(#_YX=~vOIoZw8r?&Ae5zf#{NXr9{5`NzRZde7q60d`gXrldT;Y3oA zw(Nx9q;g_EVwZt~+9Ug+2NgSfWC&X87@!Vet__<*`0qhL?*~2k-w|W*1}Rry9Q)<= zcN{dPZAZ>3KrT$+m!T?XaasCQKz}bIei*q?J;E}nC*y5iM(N9-SSzi~H(c3P?C{lI z)QQfRkjpsAI$GpGN?^)`{m{dXLrgb0Di6%LuA;?y1^qxU19mSq|4b+15fRX zV#)q<4kh&n{BrqDN;_El(VL>sn!nVfMf4`BclKGHDuV8V(&K1BT- z>ZWKN=CxWDW_PsCn5Un|P@`hkN#;qG<1C<5j6znfB}X$KdS}m4WjUkV95RO%FX`vt zO=*n3x5_)>=SHy!a~$O(HTO`Xs$3{wtx-1NNJYoUY^CL@o{?D2w#9P5bzk8u<(y0M z%`i_rdt8@B`;@@_$CiSnqtCStWfgl8Ep1Ll<54O_+aAHlan?~+;M6qqgs$b$pRX?; zN^1{TH|%fJDmJg)8RX@9v0eqAOkxBcEPTk|2Z%p){)2;Gz(~(MK=_n1uy7w3eI~%G z`3DG}p2r6X|97CpA0&NVgDk-6;(^hh{&091A0Yf1wC{t1&mEixDIe$=rWZCU{YH>V zdxBOGZ8c!9Ia=abtC!6FXu5A%d` z*X+;YpJ?(!FQ8l*y(t0bOR`s>c4(;KSgr-q{!`K_eL1Xm`yLRV5zLE{QQIceux5wi zs;hPNX<%a#8SUzR25oa%Oeg8^3-(V5(gdgM4f$$i$=y zZqkuYu#pcfuQoYt3UHi9(+n)H-dW)vS*e~}ss?-JD62D|A}jQZ@v&Kwi;|!$Inu|M z!YP^;QZnkhH_t`OMY&}Rv(0&%$ro;w>-y?Rx+j;0GY8J%I)vjH_vfDg^_Zjl5!$%s zh!0a|m1~()Rt|ni##L9}EHC?w7+>}NMf<}Re5vE%zeo)q1MUVZRFS|#E*5RWr7FJB z`eq+3ab1T~n#bj{lY+GRvHSV7mZm)QccVEb74%a_WE_2>pF-uY+ix&miq~~HQEERA ziV+iCM}?5h?lFv)`aB%v*-mu5g|R%OQq|WGQF{0}+@H~Yo9Avoc=gy1o}Dp#_K2hQV4?{9D19C6ZS0yBf75&S^DHsrB7mxxm_ES z1$7t4j`J~G!}%r60Y4V+m7_;XKSr0XRfcDc^NXuE<%wu{PxJ4O=0rInJ`2G`OO7J( zyo45M*^u)|^C*1tm1sQLo}U+LcFMs}CQTs5IfvEVSN-yF+WC3$kzEwxOMb1TAVx?3 z-rA%lKNIikqWf1oA>>;(PTGV%1T%7{HCpE1({~ENTkW*q>*iV1 zdJN^DIS_A+T3#uyt74@MIp4_u*f;y*wP+RUDP6AB@JtWl-Z_OY-C6k-njE>a`W{7& zx7G~LOAu?fAH#lgU(fBP(6hu|qqi+o_9rzd(?jwv*;Oe)UA!sGK3= z`L)x~O+3w}c-b?WJHCK&)L)co?$jQ4pl$x{I9#4^dl4`RkLT%5;rA?7gMx__bHY7prQmX*^~;#A+`i4^n(XgM zvC2qiY7H}Vdsr_3Us@$W`zPtEb79Xv^`e7|tCBXP`G163d&NG>3{+lO(g z=mO>}&xKq}%88tkYN=;WpeI2F)b3WOY^w%rXkk?&?IEX&Uhjy;+s9c)iqRIOPQ<(W zn3MFYjDo&VEofH13i`eZnoOV;J!PP68~0ER&UW}G>P#msGoFy9JXbvF5u(f}+Ou+| zdltDo`=za)Lkxb9_0$9$TN@uBcHs(~zVQ&!2*QkUHdE3uY}Qk*=qUmAN9854JI3nC;5Uc#m=;M@gya^<&;g7o0OUiq5M{kKi3MO2i5BQ-MSk_`nq%aQOn+zle0k4 z(-ovoD_r2c_L9(N4lSBa;=r8?j-OdygbW@BwJ0@#;Z{Av5w0Q}ubUlyJ$ljfJcz?F zJeQ^Co;Vk1^HM8wE-iJoY!+plCt5A6{Www9kF$OKI5E_ZGiCchC(2S?UGYqRmAn$1 z1-qYZ4oI7aKk+uTx1U@;c@mK4>K38x0ZLGJGSNTfsw1Q)#ac#W*El$X)(AP9@{Za< z?K$r@OcyO5Jc}Z^awlqIJO#YGL(^VFS@q!*yc)=t`$C+JoP!>$Z6^?S>4ZUvq-T;% zx05&YkSkQ&^XPJ^0k>~c$-#8B#3;!u3`m6t%+-1h&2*|)P0whV)m(Yg7US%q#DLX= z`z)Ldlsmj1br#kKx{io-cn?Zo3h-_LZSj{l^c!S$5blUlc74nxYl&t~1j0AU6k<=nBf~LyQ?p zb-RO`{`Ew&BPq2{1gw~s*r0V&e;*883SB)utAtJAc)Wik%B(+w5}ZsNPBJeyi`^ke zBgX(KG+2V-0IIo*o5B@q&T^C1Ja!)V`t6QkdW<2BrY0xYj7cq8hV2vbv`K9}3%F`_ z#})vaSt>k2>8NPd(!ozf56su=W_6I)Nt2yyD0IPfFbW$LXG#?@{Wo%(frltmH4|gA z&36;J%}bgw?7h0#2=hE}W=hygo3dvydYl9$xB*l~Yn%kBU5k|rVP3=GS;t*wH~UI_ zIa-`VTsp?pIYwj!E=#PXP@)=#VAw_75rv3 z9V8gl<01BaiA%r{!HW)8Dqpt|7&=ohPo9pN=T{*yxqxAL(u>QCi;FA|&4K0AZE;8K zUrw#FXxCo2Jrplb2a=BElGwqe5#3UV*K5J-$=lWNu^I&yYBG^ht#jpsa1duVjRu+y zRMBr~MI) z&RXhDb$l#>5w^-hZdj~t3uf5hzI`npL(Vu#J1z$b7FIoLU}+ za87d^&p@}n1UXj~s_Bw!5xkyUyhaN)xYoWHbPoryKSQ^SSzQJuxCq!4T{b}<)*HW# z8%1Bjz1*mA_(hlv1>6pO0>4$ckJuN4n7&6=AA4m5wZ}rBf(sk{B1~1@?A?a};+^n* zgpSzwKDiyf2kky?Qm@}01Gep2(T<}83F}!pF zudn#u;zo#R+lRbV+mkG@gKCG0L%kq+6W)2=a7TF;{l>?ohn(WXC0>T@uoUrdWw`7! z9W>8qoEwa8I7Vg#jMv@jJJ59AjUi+;XhRsl^1=cEqbb5Y}; zOQV-ik~G7217HrB$D(mJ+1U?zf+^ZfC;k3Rks3SwSYr8(G1(!9m$Kt5ddy{?+4TfW z|4aCfcwRy(`HnZ*L*BssK-tNPj)wJbxr9!EX(VUqfU zU_cv}W;z^Pvpx#P?9fFnjdhw2QAq>3i`T~anl07g@6qKW$I5I|U&nsyozVN~DhbSb z(ji>NnvGoSa#TnquG~*PjG`Q+3iD2Pds%Tbws&aXsfZx!!u_yA%1b?FxKnW;5^0|$3CgSPVR`C*k-57 zsL*HcFEPbI0l6C9D0VIm=T;%NsBez47IeZZF{BbXfD|IVM(~ewf#a&aPg`~eZ&ijf z{tR;ceIV1V=X0WSz;v_Umt!-->s4SbH)X|&FHA+K<(bs7uOr;BtXZPcR*tUD%A zo^As(LfmF>JG?45yFG|~;Gnp(U>{2GJo{6ie-*!d;OzlW-5(`FBljyG2C`u1(me+c zW2UMc<+2_aLN1V=;W#}Lp`GdE0-yUOq^Q{zFYQ{U`oLk5{&x6vu-GAJZhmb34mGh=SKhu2?t%PT(?EGKx4Y;gc0cWV} zq}H@=v+VSB1>20yOmNeVDNvqP(3EJ2mi!fa@p_GOn%>X7rf`3Y<4$XVZZB$X^O)my z@@&X|zI|ra@-+@Ns?lx{J6@FIsga4Ega3UE?4XCSR9rkoY1*a3Qsb1vKmJ&k;} z=Uez@CuKcl9cQAit!Ukd_0X;RW#LIO;>6u)zdTDKHMTfG%C0C5Bj`E4y&`xx>kOrK z(s}8u$X2HbO0@09t3j#NyP&(^AnXn;8hsCfy)wP(Obn^(&$nY`oac*%aCb%Jph{CZ03y627OCvr z%jqF%VwKc@u%4xPo{<(Gtcz{Y5%<>~=2$o$$u7q*pR&rAU1$leJnkw|8q$uS#5yja zsI`yxLQ$7i1~o10TAUb)+t6PH1&FQomu=A!)H58RZO>N=D4Ax^ihFm0(unsJ-Pxz; zd@u)&3ly~~$g9M~w_&KwndWQ>!4S37GE#kC1AJ$#(Fs8NI}Qg@(!SC$0Xk4lF0U5o zxP!1RqQ95GlS)%!;jB5cf9ZUVH_vVcXOAQ0$qDg0mNA*|m=B+{56{~NILKQH4#(s& zod2{LBDly45R29Ga2ELSapBD#d@Tv%9lB@0L8l+> zV%iF=ca7~0-viOHYt<0W5+u)X_nj@6BhgxvLDW8KTM+}&tD3MGY<5O#Mkyv*aZj{F zl$$ulltJPz*w2}xGg5t1S8YzRj5A|l`Q)3l9B+lM)Q)23W=}*u?{hGDx+^+sTVKdC zBX?3-DIVnmBR8_y=O}K}{+tKoR=u%D2~T-Xtp$l5v>dHRT1QLL!Jc?y={bjc6r*U% zq+oO_w&mvVR~($hS_C=ZS8~Hi;R>!YX_qA9(F#kg z))qX*TJfOV3$0_FjiLQRo(r|bamXlYecHS#D=EEOVNy0Q^$IK};(ZCFC(#qOq_Rx- zd^D-1-yXS_64|%allp3~@f07MDCVR@l-HBS^LBLtt@5SYwdc!o#}(XqB;{bEKiOJe zPn;&mp~n_0OPND21SLjmnfTbpJ$liNG;`^85MIDsBJP||MR0!Wnc8TJRgAq~;~d5j zez32$w&Tm_yWqbBh-X1(w~o3ChzZ<8>`M_FfX9bIJK5}s(sOa$Y@U7*HFY%+)t9%E z&KT#Xqf)8$?B=V1<)i%M@kp#LEi~F{S}sbZ_!!0S=c|m0&qUZ7d!qO)Rt{2QSF|Lp z5qDoEwAjp7=_T|J^|aDeH5_e1YESka6s#7`X!TFPk2vb~kmDRk zUW<+!WgG9b`0tQ2d5U~aJ4kzLUWr3vU&)oBRjsou+6w(TT+ciMI&h`)T8pnhdIfKqFLxq4 zZC%_8APosw_h@Hr2**9vx-fR}WQUlCx;U#Sse&5z)#d}(`9ZmDlL9eubhna@Gx$f( z-5f%MC3`z~gZHxZcpCI_FY?Z!N7x0&o6$2uJL`K~tvg3%Yv}3Ix1WQ3LF|N4=DM$s z@czuWw9N4X#BJ_4YpbR++a^G*s8n*crCF`#O3YSQKduwv$8<>}YF4w+y^!v9Rrn@v z@zK=!CvYCZy~B>QwP884`UyQLvEm8r&gIPK@gGkv=>7~sD+-UM+Kw^}-_wZdMYB2i zxGvM_d5ibZY$nIG&Q!Bn;qVP@8v@mN5I6zGdd;C6B|q|Y^H>VbLy(Vo*vag2xwPqc zs4Ee#wX`sJItKfaZDX)@P1|M6Dzjc8sTUrW&T8cz(;4x@x4jH5H68qWh%cSD9jDCQ z8A^Jtuo8OG;l3qeR%`pFjjxoO4z{h3#)%PbU$Z|Bi|}AEch91-@EGQd?n;|i$56|8 z*y)ecL&eE;hQPb}3V+lFJBGKJliR*itPV*FcT)=#9lw*l=s|TokHhiiY@|K8cwdCp zcSz;K+Mhe3vevm1%#1yT=f*yH^z4Z5bG+{6MsjJ=2gmo91=;pe?$bIt+S{^w2%X*q zw>oR(a9a{zj^TGdY-~roo|Eu4e}tuvLMBbZ+x9BvFr^5k2Bj@$ysiY)0-|JBZOKv= z!bY|b!&YwpM&-4Wx2_i3rG-Gd&c~H)Qu1+kuO?E5Uqz8S#hY2j-}~`lu{G*Co3@o$ zMKQ2BLLZ)%5|~m>d&$#2^uO4gyQWM4`!V7W!j8%g+sb;DDTS>bzuWN`fIr;t6SaBx z+JnvM4KX5h-MOcG?eUOnS$KgK9reF!lRe@bAt#0Bn_Mn2Iw^Sx7zw@{SM^tO|Arjn z*A3}=I?4fpOPni+OZ0?^g(Z9t^%&Zm{lt*=6fG+Ej?fu|qh2w7rAIjGNw&fH;_o8q z+wP(DV#~_xjF;tlz~&3DUUD%ht$S7MYb!Li{1T*Zd^g^2O?@bd_3wfA0uI0I6&n0s9+t)Hj&@H zcWqJmy`EUpCbzALgy76^eT{k?taq?G(PxNDiR0*5aNBq}{9{+G};q%7Ajs!;CgOjaqN zYct~72Rn}=$Pr>+`0hd<>?B@=be9_AarL%yf1VIxCo|rB5bcw$dS;Xq;X0Q){kjIm z2j_ve`aDeaPFr6b7IVULr+RK8#KHMdFt)EfxHjFnNqzSQZPkBzXN^%@L>1#PTqvN) zGkj7}D0~#`t*L3GWfn<+YPU7PYkRCs{6H-E#=UH~^xNECaZmF(gFk2ceGO z8#hsG?{$_gdzQR@f7_*fQGncX*Mo^iRC}9C_qWApPrbQ_6-@ZXLZ8^1_agTktB3RN zKQFg|hlIs?<2SW=Z`?hQo-&=?+0Jx#S64c_F58`HccE2G?#Z-uXSb&Kw>O2n>`p1Q zW=+Z!L(V`dvtmsu12`vB-PzHV*;754Oh*t}r|Dl^!E}Jo0P4Mx>Os9831!gSE2-^f zHCx?oGWcEiqcEOcxdxH8HO!Kd*&h51q_RCyA=|?Wo#|{33ub#z5J^CxeqHcIX8kRs zqfW2ZK}IIiuHDF>a##HwB&=euGTP@J+aIEv-P;3THe}Q5KW2xRZbNH@j@kN8Q|UAs z;xB*R61uVZ=G$#RuK6~w0Tzv$LU_cr>>3h4gKL4lOD2v23j$EOo#~9g{@YYW zTJ6oSa%O|jKx+PdI+JY*avB2NL7s(n4gdm;O*T;f*rnV|0|>Kj5*A7TP5DK8JB2pc z`ah;fXCi-Ccp;N*^s-Nlok#{!y*fC(84Lg-_}dFAcV`>BLV(S;yU?NQY5Y;t(AA9V zu%@6NJ0tmkzLk_~N4dt$0Jnv99pVf+whCG3o<;hm)@a;xjh{!!#vTwwN|H99KIz>U zKw@JPvo%COAdiFG*o1;x!-9@}Y3cVSL^-tek68`GM7t!ct?U5v~yerq(YnvR_l0DgWB%tl~cHu8KPun*# z)y07I-(XBp()~6{IzKSvLQBBmRBFfQgY<-je!A+I(jbWy8Hj+8HloFQz?H(xY@};V zyjga68eQfLXuJv93fl#Yn4x$H(;5vHm0`I_Arsa}hXqLd%dWVk=F!(IPKN-u0@YFvRhOd8& z0icvunJ2SEw2nqPDAZm_ zWjn}u9ZI3by9C`N%I^vfyeoaJF9`kx{%!tJ{`O1C1qn}DbecOkkN+mU(QITJ&5_hb zsu=#JEZ90_1gHk&ghD!)*LzS5sMJ5y-{w&gdY5CM=GR4Qt$_Yofda&?-~OHuaM{LQ zCr|eZpvJHQY7DDrXq*S^EL#TL0Z`||ERq`ML7*TCNFo}}+baFp=206Q22%lrUZ_uw z{9fVYz1aXdg38?ttS1IOT#7ihzX4M-Yz}F*4>CQPM+GPwWgGPm9i2W@I(;bFM8x8B zEZaB{2K&R{-Z1E>a7@rXhW4n5DY8K9#t8vQIFfzBCilB!9b!_NrM1&29R!A@8r$F` zK4uYa9JUn>>lC2wYI3#{esfyoAlR>)6n!PtPU`_-()9%v#pr_Ah)PcfMAl_8=u@u^ zV$4v8BG68|Y-5T7iEJ_DkeISaOeqpm0)GlnRFVonjFJH1EKzAI0GsbpbP(CAY7#a7 zSbwjd#V;7MSAVwR2hx~xvw5LCd;Pq$jo%)bjxy9ejHetT$87(Bg5Gp{9I`IMu1C!>D(`*}L!C$In zaD)TCam|Vl>kvDPZc`@u_48J{xC(4v0BNHb0WH|P0KznXx}vLjUJRo(E(FXVKgIBD z{xVW*a^+c^uPv_oPTM9`P>~_>Pgt(N$3L{6c|6v;K+Mrm_K@54H)A_OR z1O(;6^4XolA)UL0m3S#d40&+M%J=ur_V8rnok1c78T%YC2};_o}$65i_J(30Fggj>Ej@ z-6j)AdP#<{E*2I>WTUZTEn!rF_S#612@MLC+i0*3RNP7IMGW5C=zX#ShHE zjRuqS`cGiUZMO~!4mx8T0vD#tn@+XEDr0w>{{saqowX7E1=DGp+T0%_31zSU-}d)M z_Lpc_1f?OZ1ME3j2xooJZjjY$vt-TAGD4P7qVm^>fybdW(3WfCPc;!dX%l6_N;U>% z{v1Z>7PAN}Y?{|tM%k)yi>xUn5C~BR!I&YG zL%;&mR0mLF(yRu-D$;Y+-XDdE8jaj?jogw2v0#K+N(;gdBcLd;4-;T(#L8!^cg9vH zo_}i*mi44|DYOsJ&HB6G2N1sguEnJOF7Txlj2VOw4btrOf6@@7sCsoUCWkrVaDLoG zmW`l2QH(mI95^lH22Nvk;56d+M`LLnN1H{C4x3S}L)z2mXnq#~N>2%()voyta!o0f zVL`+MnXdU)WW7cO@V2ld>~KIm3d$X$g14dVI`?f1$zNvMS_-loGcT6n6mhg%dW(e< zO-5T@+b4pyH3VBxl#0gC((`OvV;O38KW+`=NLo56G2<}wYXcEC7TPy@x;%n(D~rYY z+9Ly@6!#e8srdN5+rdb0`Uu}Gyj(8 zq_@D8G*I4RBJ#i*^KWf8V17!xfCBIjfM#BThXZ0e11Uf^kvte)!~7QYo(;7E=Q$Ah;0k#!>L2>PfEa zZhRS045fIc=A6OxdbaU8BZx0?=;rZc+b^FJ=npt3e^oV;6Sw zIEbT!?Mjd&0+G{GO-5SIaEmA`Z~zSWc_YkA-=MVMnBRd2nBOIc>m)=%D(TqIuLB6> ztNC^K?FIC8A{N%k*dhjl1Y0p&w8<|TgMnfr$OfUpLZA$dp80ilfCVNoUMEA(#-jBb zZPM5VLVpWvkKv-LL0!sRBH0j-37r$^(8&OIk*wbuBbaG_M($LK2Vu+Nn>bn=ddneRutFui)RH?AO$Qg*%{GYAM$pTOa!)~CRr5!S9|?hmN7g5W%z zUsCsR>Eh$;;yOFpq2c>^TEXkIvzUm|3UT&2|#RKZksue@B9Z?x7x`?CV<0e z{)065B#5x-Q>eKG0h+&C>^g3t-R>R9rk&WQ*xu-x{}^RASvCrRaAet3z-`hHib2DK zZ7J6@wulgtzw;kRvt2h9wAlhH~2rMPZ-~(bDb2ff9PibEKR7E zbi3*dA*5T|SZJ40VCt|Kn1jkYOuz~?UZ6KpKvpkddDzkfkbn{Odsq(r*vgdFg6LAm z8b=6vX8l^S3kLfvJHN%bqb9+oH-#tW-?Km9v;{vIMKR}MiBu@_@4*;z(-DMRm?AK+ zG-a;~J8k6RDyzK$C@(XWE=0;f`-{B~9r5}1+|VCYUXT*tiRMwU1qJ^I!p^StI{_28 zwcuv@wj))wTXsqYeSjd>j(KRSA>(?bhK!4$OTa<=KO>%iq+FFnCglT+?CgA9nOO{G zSldVtQq-9b*(j@RN8p>z196j_M?kiTn_V}40*Xs>41?kt#;+`et;rk|kZ~6A)`^+@ zlQh6_W8PIG2r^Dk9(Yj7?I8t`DH4D!F6^@@fwXrHU&zHEZT>wCQl@PZ_X-8jCXoZ1 zz{ns066QY$N&yH43&mv`Llj%Skh;PlnB6Yff<$rv5)7mDEo1$?)Ah5$o|HN4&w`7( zr9(|8lwIPZz!fQvJ|i5>#7JW5u_OVxa$p;EOd=is2MJ*QYglAO7-gcW2+X|z5yy58 zF)=9o0&Xt30@j*#QDs6GLmQ6a1Wg@IO~uF&d26NFu2_eFjkWaIEj*%>kcIMMRa}Q0 zfpm!x1rVhlRa`(%a3rK*K*M#=)Io&4zaWCHti^5(>_8zrnuTwfVomuUaBQ5McN3Ef ztAlLw0?N6GA{iJGUBpRUNrFKyLujWAN(30$BxPHiE)g#`T~2yP#-+dxXuj<>UT&uC z5L$|%Au)2pC|UbW5P{oQG#YOF1GKZWA=Kb90s?`XAakoB=lRQt%l)f4{XZp0V@@WE z0CAGO4)$KSCM3cXfTC>NgpgW@CzGLFDJR}@D2wC;RA!JxT-eR6Aa3OfN~$AWt9~cl zPJi$Mf352VeYOcG(vGo+Bv_e+BUJ%GP%N$cp%{eia9CSHF`bmUg+y;wxlTAHbn#$T zxr9g6JP3LXtl~sLv((Ei={d^Dr7Ak-SR7!wTb9%DWZm_Nr=o)@BpW&WQq<*SkaIMc ze=IW@RHDHNQ6_Bb`s_wU6j*E&oiK4_tT1s=6(%kQ6l_-rAI*5Q7hgcm+MHlLH7)0? z7LJT6S1rOymJej<7bzj$t4K<__`M=Ymg$fN{s%jOOCY>3351E526`-f7h_|Kh)>av zTON#*af}&Bq{CEcOqDK7;KSKwcgK_3L>s!a^(&}%&QED?O|s4c+Wn8aIY_$-o%)_k zU^TH^*v-KpE{CUN!Ng^ToLO|si~xXd)3}O`C0yLHgo`RmxEK|#a9#a}oPOYo`VYyL z^&et8qYVqUCeEu;HaSZL#}QG1(O&NJQS^$fZbi3*Rb@&LFn{;Un9?#-obC&6LndlN zA98%XC@3I9<0tW?YP8f=JJG#T791E_xF-UWYlVgH^B6(>Lx^1$MAOoi&FK{z(gTUo zVPVz#L0#lI8r$kPO{?(0smK*s?}A+d+7^^dlRm%kL8keR6Ri$+&ZBr=-59$vb{@H? z&LbB?ZMDS&}#w|hp`bR(+^Bxxzbe7%>mUcWIk23>2?a6(6@{;Z#Nl5t>MS5+PGA2k)+BdJ0 zc+Kn5)7!RSehPIkV)Xp~?)Q~$aBayB0MU9ykAuquzKRKKSKv5phK|~k7#FPC z!78E2ur6Q`222>*8%eprquN(xfNDyP*0}Bi_dO zyn8y_{|X~77wT18eLSdOGJ1cJw-kAMbQN!ST{LTW8&K~8uBzfr*toIKd3A*M8zssL zT5Sv88sQtsyve8#d1L*O*$};gS~Z*cP{!SXpFkUY4Roc!|5ExRVfpiD{Hc<#bG(en zJ8D_KND;5n6fKYx0Ip2q&lmi6qL=7CY3L`wkIX_$^76o-DQfq zC*rr^+!tT<3L~E;qGYL=M;9x|n}>PG!0E+{gx8S=3D&(j7RsvV>i~qvTh00cP)}51 zMl&-Mw+>#x^epwo%9Wj9(d|or9IGeZOaF4<%AWy13?2VP%&OVT3;xUfI97kOV?Lzh z*Y7sCXU!Z7ZXn(GPJ~llp~Ut=l=>@W0&hp?@#TEUNo%9DSy{lJo^Yi2wzj^1&9?de ziBnS)0FNyG$)qQi`}Lxgrrns&SHJ_&S6TE`@u)UUnJ@E(_C0-OCWQ{LlV2cb`42QO z_B^`S`XQ7g;y!x&NxeZI6bwHvB5)pA{6ii&zF|Pyg|rUet*GKf5q&vk9WRIT*&GhZ zrljv)Yzl`i{P0A|9QLh%JNa6~rlb!s$(at9)_(-|ZNZ9V*gSx=k zpxgl$CiXk`+fJ}O7!zU@Kc4fddBnY@)cP*Q2A4$zMn>G?5-1M+H%`-qN7KbewX5i) zXKR6}I3d=gOxs}JU>_d2>Pg|Z88w*S6;>^Bt zW3aeVhVxbem=E~hcIw)*>Ce4f$QyiNuPE8dH$IF#U zalAHlbp;ykI904x^OuUFg|_0t9SQuwBtIp;tmx{F>X}M4ST2l47 zLRBSHV=`qL7q#5kVzt&cI#VlNs^m$Jy}8qK7pF?&UnyQa*55xk+|U0FAC{jZ8td;r z*gq%;Lye5p(FXik-~w(`1nAffbihZ z!GWQ{f&RfG{rwjY4GxV@968*7+#RDCQ^n(bf^<3?3X9Kb#*J93DD&VBqjz|G~m||B<1g;o-so z;CW;S!~gsDd-yx5#ae#0^jh)iU9v#^-`;PO(#46p#pUh$jmx_6xoWLEt@G+`vAX|r zc4lt&wM%!4&i{J9iL_#(T)tam{^Zxl#yJ+3|dJaYZ&W2X%Fq!~OsStDrMcEEet-rGJ+|t9w%Q zYx7f6Z>R-Qy<4QdpMcbT8o*W6;xy2^OUxcgneMBqQEvp5hhMdf3V}??u@BjJZ zTw=k#+{n~au2Q-*S*zw?;uI@y6bpUM8WfA}^SZoB!}9Ay;qv8Eb5pg_>{Jm69iuao z#Y(AGEU5K|vUM1W%POmG9a^1Xh#gWnG-~axQ~4Q~Z1|R1SZL8u{XeGQex!jLG2K>; zmuDtQm%5J2kA-`pSRIE^*uMHy{>n(@Qk8g|&1^YG195B))^X*kGc9SKZi-a41zh=) zSMt-KhhM%sQr;G*CSkrUWin^--zrz0E6x-#dgaRMfxdyh{=R;{&kb1K30+%VnyJ>n z;af-b*XvxRB(`~*^szL<+<4@ED|hT z8(3l_kd(&Z$ZQF=`?fI`TAHlFIx$9Cl0dmQ;5aoMi4qvGC$aAB8L~IAUMq3yu#^(0 zvRbXd>eew?ZGo1ufb@oyE38GQ&m+-l5oQAA7GuwFzSRFyB3dh}v&HexVX-%!h)`@$ z7DaEf2O)x+?NP!6-x9BqK+69w5$9Ef;#9F#+;T#GTJiR0EEnLRjG`;!Hgm5x0`(5~ zYHMr7+cVW8t(78V*a2sN%46HjYTxt4saYGr((eCFq|nMq6#AT3(ql7FC$oBFsz#xl z`cg=n+sNTKoI-iQ+^a=9gL*9umILi0UH|AxkUlZC+!7rU%$@d4ek19ItkJfw3iC zB|;Eo1T2>l6ws=<*#aiPmUHscN*S1(nRWi4K5}$cxu)7TE{5N=YI$mo?zu0zKH0{7 z+vSl6{MIoGHBvXs;z`IUx->(9B>7Jy_F%(HVvxNGf9S<>6{d>qLPf?vW!2^~soWJlCGQW~#**e1#=Ga?2bqWq%MIuA*`U z{I@x1eALRgGjmwinJ=fz(Ad>#tvKE1CP%f8+XU4<_}R-dm!__sy*gVgxXfqfN>hbm zWi>qf@r6r_vz8I9e>bw+#t@e-%{&hM2v0fn<7p_wVx?9pwrEI>UgvMYd0Cn$jf*FK z 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ℜ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 z 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 QyoYM=KXd8-r!V#Y0 Date: Sun, 10 Mar 2013 20:26:31 -0300 Subject: [PATCH 0056/1224] # Updated code to parse -debug option and correctly generated .pdb info --- src/ScriptCs.Core/DebugFilePreProcessor.cs | 1 + .../Wrappers/CompilationWrapper.cs | 8 +++-- .../Wrappers/SubmissionWrapper.cs | 11 +++---- src/ScriptCs/Program.cs | 29 +++++++++++++++++-- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/ScriptCs.Core/DebugFilePreProcessor.cs b/src/ScriptCs.Core/DebugFilePreProcessor.cs index ff133bb5..cafe47cd 100644 --- a/src/ScriptCs.Core/DebugFilePreProcessor.cs +++ b/src/ScriptCs.Core/DebugFilePreProcessor.cs @@ -9,6 +9,7 @@ public class DebugFilePreProcessor : FilePreProcessor { private const string SystemDiagnosticsUsing = "using System.Diagnostics;"; + [ImportingConstructor] public DebugFilePreProcessor(IFileSystem fileSystem) : base(fileSystem) { diff --git a/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs b/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs index d0d10040..a73c83af 100644 --- a/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs @@ -4,13 +4,17 @@ namespace ScriptCs.Wrappers { using System.IO; + using Roslyn.Compilers.CSharp; + public class CompilationWrapper : ICompilation { private readonly CommonCompilation _compilation; - public CompilationWrapper(CommonCompilation compilation) + public CompilationWrapper(Compilation compilation) { - this._compilation = compilation; + this._compilation = compilation.UpdateOptions( + compilation.Options.WithDebugInformationKind(DebugInformationKind.Full) + .WithOptimizations(false)); } public ICompilationResult Emit(Stream outputStream, Stream pdbStream) diff --git a/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs b/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs index fdf17e4f..31b3f78c 100644 --- a/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs @@ -1,11 +1,8 @@ -using Roslyn.Scripting; +using Roslyn.Compilers.CSharp; +using Roslyn.Scripting; namespace ScriptCs.Wrappers { - using System.Threading; - - using Roslyn.Compilers; - public class SubmissionWrapper : ISubmission { private readonly Submission _submission; @@ -19,8 +16,8 @@ public ICompilation Compilation { get { - return new CompilationWrapper(this._submission.Compilation); + return new CompilationWrapper((Compilation)this._submission.Compilation); } } } -} +} \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 2080ce22..b8ac4a90 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -11,16 +11,34 @@ private static void Main(string[] args) { if (args.Length == 0) { - Console.WriteLine("Usage:\r\n\r\nscriptcs [file]\r\n"); + WriteUsageMessage(); return; } var script = args[0]; - + bool debug = false; + + if (args.Length == 2) + { + var secondParam = args[1]; + if (secondParam.Equals("-debug")) + { + debug = true; + } + else + { + Console.WriteLine("Unrecognized parameter {0}.", secondParam); + WriteUsageMessage(); + return; + } + } + + var contractsMode = debug ? Constants.DebugContractName : Constants.RunContractName; + var container = ConfigureMef(); var fileSystem = container.GetExportedValue(); var resolver = container.GetExportedValue(); - var executor = container.GetExportedValue(Constants.RunContractName); + var executor = container.GetExportedValue(contractsMode); var scriptPackManager = new ScriptPackResolver(container); try @@ -40,6 +58,11 @@ private static void Main(string[] args) } } + private static void WriteUsageMessage() + { + Console.WriteLine("Usage:\r\n\r\nscriptcs csxFile [-debug]\r\n"); + } + private static CompositionContainer ConfigureMef() { var catalog = new AggregateCatalog(); From 06ed00fd78bcb116858912c545b38e24172680a9 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 10 Mar 2013 22:00:08 -0300 Subject: [PATCH 0057/1224] Update CONTRIBUTING.md Updated CONTRIBUTING.md to specify that the `this` keyword should be avoided. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 654db776..b4c2c4a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ If the issue isn't marked with one of the above tags it's either still under dis ## Code Style * Indent with spaces (4) instead of tabs. -* Prefix private instance field names with an underscore and be camel-cased. +* Prefix private instance field names with an underscore and be camel-cased. The `this` keyword should be avoided. * Use the `var` keyword unless the inferred type is not obvious. * Use the C# type aliases for types that have them (ex. `int` instead of `Int32`). * Use meaningful names (no hungarian notation). From 4b8e5f8ad3ee040bb3db6e533323548f0d8ebf4c Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 10 Mar 2013 22:06:02 -0300 Subject: [PATCH 0058/1224] # Removed this keyword before instance members and using statements inside namespace declaration --- src/ScriptCs.Core/CompilationResult.cs | 5 ++--- src/ScriptCs.Core/DebugScriptExecutor.cs | 6 +++--- src/ScriptCs.Core/FilePreProcessor.cs | 2 +- src/ScriptCs.Core/IFileSystem.cs | 3 +-- src/ScriptCs.Core/ScriptExecutor.cs | 4 ++-- .../Wrappers/CompilationWrapper.cs | 12 +++++------- .../Wrappers/ScriptEngineWrapper.cs | 18 +++++++++--------- src/ScriptCs.Core/Wrappers/SessionWrapper.cs | 14 +++++++------- .../Wrappers/SubmissionWrapper.cs | 4 ++-- .../DebugFilePreProcessorTests.cs | 17 ++++++++--------- .../DebugScriptExecutorTests.cs | 3 +-- 11 files changed, 41 insertions(+), 47 deletions(-) diff --git a/src/ScriptCs.Core/CompilationResult.cs b/src/ScriptCs.Core/CompilationResult.cs index 2603f123..eecd296f 100644 --- a/src/ScriptCs.Core/CompilationResult.cs +++ b/src/ScriptCs.Core/CompilationResult.cs @@ -10,9 +10,8 @@ public class CompilationResult : ICompilationResult { public CompilationResult(CommonEmitResult emitResult) { - this.Success = emitResult.Success; - - this.ErrorMessage = this.RetrieveErrorMessage(emitResult.Diagnostics); + Success = emitResult.Success; + ErrorMessage = RetrieveErrorMessage(emitResult.Diagnostics); } public bool Success { get; private set; } diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index ea79cf1b..ce9b00c1 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -7,7 +7,7 @@ namespace ScriptCs [Export(Constants.DebugContractName, typeof(IScriptExecutor))] public class DebugScriptExecutor : ScriptExecutor { - private readonly ICompiledDllDebugger compiledDllDebugger; + private readonly ICompiledDllDebugger _compiledDllDebugger; [ImportingConstructor] public DebugScriptExecutor( @@ -18,7 +18,7 @@ public DebugScriptExecutor( IScriptHostFactory scriptHostFactory) : base(fileSystem, filePreProcessor, scriptEngine, scriptHostFactory) { - this.compiledDllDebugger = compiledDllDebugger; + _compiledDllDebugger = compiledDllDebugger; } public DebugScriptExecutor( @@ -51,7 +51,7 @@ protected override void Execute(string absolutePathToScript, ISession session, s if (result.Success) { - this.compiledDllDebugger.Run(outputPath, session); + _compiledDllDebugger.Run(outputPath, session); } else { diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 975342f5..4d99ee98 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -25,7 +25,7 @@ public string ProcessFile(string path) var parsed = ParseFile(entryFile); // item1 === usings; item2 === code - var result = this.GenerateUsings(parsed.Item1); + var result = GenerateUsings(parsed.Item1); result += _fileSystem.NewLine + parsed.Item2; return result; diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index d7282763..820e488f 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; +using System.IO; namespace ScriptCs { - using System.IO; - [InheritedExport] public interface IFileSystem { diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 188cb22e..b6a53ac8 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -30,8 +30,8 @@ public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) { - this._scriptEngine.AddReference("System"); - this._scriptEngine.AddReference("System.Core"); + _scriptEngine.AddReference("System"); + _scriptEngine.AddReference("System.Core"); var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); diff --git a/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs b/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs index a73c83af..5a46ff77 100644 --- a/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/CompilationWrapper.cs @@ -1,25 +1,23 @@ -using Roslyn.Compilers.Common; +using System.IO; +using Roslyn.Compilers.CSharp; +using Roslyn.Compilers.Common; namespace ScriptCs.Wrappers { - using System.IO; - - using Roslyn.Compilers.CSharp; - public class CompilationWrapper : ICompilation { private readonly CommonCompilation _compilation; public CompilationWrapper(Compilation compilation) { - this._compilation = compilation.UpdateOptions( + _compilation = compilation.UpdateOptions( compilation.Options.WithDebugInformationKind(DebugInformationKind.Full) .WithOptimizations(false)); } public ICompilationResult Emit(Stream outputStream, Stream pdbStream) { - var emitResult = this._compilation.Emit(outputStream, pdbStream: pdbStream); + var emitResult = _compilation.Emit(outputStream, pdbStream: pdbStream); return new CompilationResult(emitResult); } } diff --git a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs index 57c6c347..b98afd72 100644 --- a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs @@ -6,50 +6,50 @@ namespace ScriptCs.Wrappers { internal class ScriptEngineWrapper : IScriptEngine { - private CommonScriptEngine scriptEngine; + private CommonScriptEngine _scriptEngine; [ImportingConstructor] public ScriptEngineWrapper() { - this.scriptEngine = new ScriptEngine(); + _scriptEngine = new ScriptEngine(); } public ScriptEngineWrapper(CommonScriptEngine engine) { - this.scriptEngine = engine; + _scriptEngine = engine; } public string BaseDirectory { get { - return this.scriptEngine.BaseDirectory; + return _scriptEngine.BaseDirectory; } set { - this.scriptEngine.BaseDirectory = value; + _scriptEngine.BaseDirectory = value; } } public void AddReference(string assemblyDisplayNameOrPath) { - this.scriptEngine.AddReference(assemblyDisplayNameOrPath); + _scriptEngine.AddReference(assemblyDisplayNameOrPath); } public ISession CreateSession() { - return new SessionWrapper(this.scriptEngine.CreateSession()); + return new SessionWrapper(_scriptEngine.CreateSession()); } public ISession CreateSession(THostObject hostObject) where THostObject : class { - return new SessionWrapper(this.scriptEngine.CreateSession(hostObject)); + return new SessionWrapper(_scriptEngine.CreateSession(hostObject)); } public ISession CreateSession(object hostObject, System.Type hostObjectType = null) { - return new SessionWrapper(this.scriptEngine.CreateSession(hostObject, hostObjectType)); + return new SessionWrapper(_scriptEngine.CreateSession(hostObject, hostObjectType)); } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs index c5408803..dc49b39e 100644 --- a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs @@ -8,14 +8,14 @@ public class SessionWrapper : ISession public SessionWrapper(Session session) { - this._session = session; + _session = session; } public IScriptEngine Engine { get { - return new ScriptEngineWrapper(this._session.Engine); + return new ScriptEngineWrapper(_session.Engine); } } @@ -23,28 +23,28 @@ public Session WrappedSession { get { - return this._session; + return _session; } } public object Execute(string code) { - return this._session.Execute(code); + return _session.Execute(code); } public void AddReference(string assemblyDisplayNameOrPath) { - this._session.AddReference(assemblyDisplayNameOrPath); + _session.AddReference(assemblyDisplayNameOrPath); } public void ImportNamespace(string @namespace) { - this._session.ImportNamespace(@namespace); + _session.ImportNamespace(@namespace); } public ISubmission CompileSubmission(string code) { - var submission = this._session.CompileSubmission(code); + var submission = _session.CompileSubmission(code); return new SubmissionWrapper(submission); } } diff --git a/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs b/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs index 31b3f78c..cdfab69a 100644 --- a/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/SubmissionWrapper.cs @@ -9,14 +9,14 @@ public class SubmissionWrapper : ISubmission public SubmissionWrapper(Submission submission) { - this._submission = submission; + _submission = submission; } public ICompilation Compilation { get { - return new CompilationWrapper((Compilation)this._submission.Compilation); + return new CompilationWrapper((Compilation)_submission.Compilation); } } } diff --git a/test/ScriptCs.Core.Tests/DebugFilePreProcessorTests.cs b/test/ScriptCs.Core.Tests/DebugFilePreProcessorTests.cs index 03362a3f..aec87b75 100644 --- a/test/ScriptCs.Core.Tests/DebugFilePreProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/DebugFilePreProcessorTests.cs @@ -1,13 +1,12 @@ -using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; using Should; using Xunit; namespace ScriptCs.Tests { - using System; - using System.Collections.Generic; - using System.Linq; - public class DebugFilePreProcessorTests { private static DebugFilePreProcessor CreateFilePreProcessor(Mock fileSystem = null) @@ -19,7 +18,7 @@ private static DebugFilePreProcessor CreateFilePreProcessor(Mock fi public class TheParseFileMethod { - private List fileWithoutSystemDiagnostics = new List + private List _fileWithoutSystemDiagnostics = new List { "using System;", "using System.Collections.Generic;", @@ -27,7 +26,7 @@ public class TheParseFileMethod @"Console.WriteLine(""Goodbye Script 3"");" }; - private List fileWithSystemDiagnostics = new List + private List _fileWithSystemDiagnostics = new List { "using System;", "using System.Diagnostics;", @@ -50,7 +49,7 @@ public void ShouldAddSystemDiagnosticsUsingIfItDoesNotExistInOriginalCode() { // arrange const string FilePath = "C:\filePath.csx"; - _fileSystem.Setup(fs => fs.ReadFileLines(FilePath)).Returns(this.fileWithoutSystemDiagnostics.ToArray()); + _fileSystem.Setup(fs => fs.ReadFileLines(FilePath)).Returns(_fileWithoutSystemDiagnostics.ToArray()); var preProcessor = CreateFilePreProcessor(_fileSystem); @@ -66,7 +65,7 @@ public void ShouldNotAddSystemDiagnosticsUsingIfItExistsInOriginalCode() { // arrange const string FilePath = "C:\filePath.csx"; - _fileSystem.Setup(fs => fs.ReadFileLines(FilePath)).Returns(this.fileWithSystemDiagnostics.ToArray()); + _fileSystem.Setup(fs => fs.ReadFileLines(FilePath)).Returns(_fileWithSystemDiagnostics.ToArray()); var preProcessor = CreateFilePreProcessor(_fileSystem); diff --git a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs index 44d631d1..cbe51d6d 100644 --- a/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs @@ -3,13 +3,12 @@ using System.Linq; using Moq; using ScriptCs.Contracts; +using ScriptCs.Exceptions; using Should; using Xunit; namespace ScriptCs.Tests { - using ScriptCs.Exceptions; - public class DebugScriptExecutorTests { public static DebugScriptExecutor CreateScriptExecutor( From b1e70e61a199a0bf622b4aa7b85dc78a5c55b770 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 10 Mar 2013 23:56:57 -0300 Subject: [PATCH 0059/1224] # Added docs/DEBUGGING.md --- docs/DEBUGGING.md | 112 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 docs/DEBUGGING.md diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md new file mode 100644 index 00000000..c82ec184 --- /dev/null +++ b/docs/DEBUGGING.md @@ -0,0 +1,112 @@ +scriptcs Debugging overview +=========================== +This document explains the steps required to debug .csx files with scriptcs. This document also goes over the limitations of the current debugging approach and the reasons for those limitations. + +What you will be able to do +--------------------------- +* Use [mdbg](http://msdn.microsoft.com/en-us/library/ms229861.aspx) to debug .csx scripts. +* Place breakpoints in your code using `Debugger.Break();`. No need to add the `using System.Diagnostics;` as it is automatically added when debugging. We are considering the usage of `#debug` instead of `Debugger.Break();` as it is less verbose. The downside is that you would lose direct portability to a VS project (feedback?). +* Compile your .csxs to .dlls. + +What you won't be able to do +----------------------------- +* Use VS to debug. +* Use mdbg to get the current line of code. + +The aforementioned limitations are due to the fact that: +1. The compiled code is not a 1 to 1 mapping of the .csx files. +2. The generated .pdb files do not point to the source file (due to 1.) + +Debugging with scriptcs +----------------------- +The following example shows how you can debug the [WebApiHost sample](https://github.com/scriptcs/scriptcs/tree/dev/samples/webapihost) using scriptcs. This procedure assumes that you have the .csx, packages.config and Packages folder already setup. +Additionally, you should have mdbg.exe already installed with support for .NET 4 configured in your PATH (if you have VS installed it should be under **C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools** and **C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools\x64**). This sample uses the x64 version, but you might need to use the other one (this is explained below). + +1. Open server.csx and add a debugger break to the **TestController**'s **Get** method: + + ``` + public string Get() { + Debugger.Break(); + + return "Hello World"; + } + ``` + +2. Open your two instances of your favorite command line tool (let's call them *console1* and *console2*) and cd to the directory where server.csx is located. + +3. In *console1* enter `scriptcs.exe server.csx -debug`. The output should look like the following one (notice the scriptcs automatically halts before starting to run your scripts' code): + + ``` + PS C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug> .\scriptcs.exe server.csx -debug + Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.AspNet.Web + Api.Client.4.0.20710.0\lib\net40\System.Net.Http.Formatting.dll + Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.AspNet.Web + Api.Core.4.0.20710.0\lib\net40\System.Web.Http.dll + Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.AspNet.Web + Api.SelfHost.4.0.20918.0\lib\net40\System.Web.Http.SelfHost.dll + Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.Net.Http.2 + .0.20710.0\lib\net40\System.Net.Http.dll + Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.Net.Http.2 + .0.20710.0\lib\net40\System.Net.Http.WebRequest.dll + Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Newtonsoft.Json.4.5. + 11\lib\net40\Newtonsoft.Json.dll + Attach to process 7148 and press ENTER. Then use the 'go' command in the debugger. + ``` + +4. In *console2* execute `mdbg.exe` and run `processenum`. The output should look like this (the important entry is 1988, the scriptcs.exe one, which should match the number displayed by scriptcs. If it is not there, use the other version of mdbg.exe): + + ``` + PS C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug> mdbg.exe + MDbg (Managed debugger) v4.0.30319.1 (RTMRel.030319-0100) started. + Copyright (C) Microsoft Corporation. All rights reserved. + + For information about commands type "help"; + to exit program type "quit". + + mdbg> processenum + Active processes on current machine: + (PID: 2156) C:\Windows\Explorer.EXE + v4.0.30319 + (PID: 4056) C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe + v2.0.50727 + (PID: 6548) C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe + v2.0.50727 + (PID: 7148) C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\scriptcs.exe + v4.0.30319 + ``` + +5. Attach to 7148 by running `attach 7148` in *console2*. +6. In *console1* press ENTER to continue start running your scripts. +7. In *console2* run `go` (it's like F5 in VS). In this case, mdbg.exe will not return the prompt as it is waiting for the breakpoint to be hit, but `Listening...` will be displayed in *console1* (among other things). +8. Open your web-browser of choice and browse http://localhost:8080/api/Test. +9. Go to *console2*. mdbg.exe will have stopped at the breakpoint displaying the following: + + ``` + STOP UserBreak + located at line 17 in + [p#:0, t#:8] mdbg> + ``` + +When using only one file, the correct line number is displayed (or almost). This could get complicated if you have multiple files and various breakpoints. That would be another of the uses for `#debug`, which could be replaced by the following so scriptcs could give you an idea of where you are standing: + +``` +Console.WriteLine("{0}:{1}", originalFileName, originalLineNumber); +Debugger.Break(); +``` + +Now you can run any mdbg.exe command. For example, running `print this` outputs the following: + +``` +[p#:0, t#:8] mdbg> print this +this=Submission#0+TestController + _disposed=False + _request=System.Net.Http.HttpRequestMessage + _modelState=System.Web.Http.ModelBinding.ModelStateDictionary + _configuration=System.Web.Http.SelfHost.HttpSelfHostConfiguration + _controllerContext=System.Web.Http.Controllers.HttpControllerContext + _urlHelper= +``` + +Inside the bin folder you will find server.pdb and server.dll. + +If you have any feedback feel free to open an issue. \ No newline at end of file From be0e90d204633d9cae495e443c25ac952207133e Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Mon, 11 Mar 2013 01:42:07 -0300 Subject: [PATCH 0060/1224] Updated README.md with link to debugging docs --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f517e135..fe09b69f 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,9 @@ This will launch a web api host. ## How it works scriptcs relies on Rosyln for loading loose C# script files. It will automatically discover nuget packages local to the app and load the binaries. +## Docs +* [Debugging overview & How To](https://github.com/scriptcs/scriptcs/blob/dev/docs/DEBUGGING.md) + ## What's next * Adding support for pluggable recipe "packs" for different frameworks. From 61a8a39ab4ef183d3d804d39978e72801b72081d Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Mon, 11 Mar 2013 11:36:34 -0400 Subject: [PATCH 0061/1224] refactored roslyn out of core to fix #90 in preperation for #80 --- ScriptCs.sln | 13 ++ src/ScriptCs.Contracts/IScriptPack.cs | 1 - .../ScriptCs.Contracts.csproj | 11 -- src/ScriptCs.Core/IScriptEngine.cs | 13 +- src/ScriptCs.Core/ISession.cs | 9 - src/ScriptCs.Core/ScriptCs.Core.csproj | 12 -- src/ScriptCs.Core/ScriptExecutor.cs | 65 ++------ .../Wrappers/ScriptEngineWrapper.cs | 48 ------ src/ScriptCs.Core/Wrappers/SessionWrapper.cs | 29 ---- src/ScriptCs.Core/packages.config | 2 - .../Properties/AssemblyInfo.cs | 36 ++++ .../RoslynScriptEngine.cs | 47 ++++++ .../RoslynScriptPackSession.cs} | 14 +- .../ScriptCs.Engine.Roslyn.csproj | 76 +++++++++ .../packages.config | 0 src/ScriptCs/Program.cs | 4 +- src/ScriptCs/ScriptCs.csproj | 4 + .../ScriptExecutorTests.cs | 154 ++---------------- .../Properties/AssemblyInfo.cs | 36 ++++ .../RoslynScriptEngineTests.cs | 89 ++++++++++ .../ScriptCs.Engine.Roslyn.Tests.csproj | 88 ++++++++++ .../packages.config | 8 + 22 files changed, 434 insertions(+), 325 deletions(-) delete mode 100644 src/ScriptCs.Core/ISession.cs delete mode 100644 src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs delete mode 100644 src/ScriptCs.Core/Wrappers/SessionWrapper.cs create mode 100644 src/ScriptCs.Engine.Roslyn/Properties/AssemblyInfo.cs create mode 100644 src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs rename src/{ScriptCs.Core/ScriptPackSession.cs => ScriptCs.Engine.Roslyn/RoslynScriptPackSession.cs} (56%) create mode 100644 src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj rename src/{ScriptCs.Contracts => ScriptCs.Engine.Roslyn}/packages.config (100%) create mode 100644 test/ScriptCs.Engine.Roslyn.Tests/Properties/AssemblyInfo.cs create mode 100644 test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs create mode 100644 test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj create mode 100644 test/ScriptCs.Engine.Roslyn.Tests/packages.config diff --git a/ScriptCs.sln b/ScriptCs.sln index 8fa69ec7..24acd26f 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -28,6 +28,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{9659F354 build\ScriptCs.Version.props = build\ScriptCs.Version.props EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn", "src\ScriptCs.Engine.Roslyn\ScriptCs.Engine.Roslyn.csproj", "{E79EC231-E27D-4057-91C9-2D001A3A8C3B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn.Tests", "test\ScriptCs.Engine.Roslyn.Tests\ScriptCs.Engine.Roslyn.Tests.csproj", "{28D11DE5-9F98-4E0A-8CCC-9CDC19110451}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,6 +58,14 @@ Global {AC228213-7356-4F0D-BA48-EBA5FB8A7506}.Debug|Any CPU.Build.0 = Debug|Any CPU {AC228213-7356-4F0D-BA48-EBA5FB8A7506}.Release|Any CPU.ActiveCfg = Release|Any CPU {AC228213-7356-4F0D-BA48-EBA5FB8A7506}.Release|Any CPU.Build.0 = Release|Any CPU + {E79EC231-E27D-4057-91C9-2D001A3A8C3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E79EC231-E27D-4057-91C9-2D001A3A8C3B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E79EC231-E27D-4057-91C9-2D001A3A8C3B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E79EC231-E27D-4057-91C9-2D001A3A8C3B}.Release|Any CPU.Build.0 = Release|Any CPU + {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -61,5 +73,6 @@ Global GlobalSection(NestedProjects) = preSolution {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} {AC228213-7356-4F0D-BA48-EBA5FB8A7506} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} + {28D11DE5-9F98-4E0A-8CCC-9CDC19110451} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} EndGlobalSection EndGlobal diff --git a/src/ScriptCs.Contracts/IScriptPack.cs b/src/ScriptCs.Contracts/IScriptPack.cs index 0174b0e6..3b03ead8 100644 --- a/src/ScriptCs.Contracts/IScriptPack.cs +++ b/src/ScriptCs.Contracts/IScriptPack.cs @@ -3,7 +3,6 @@ using System.ComponentModel.Composition; using System.Linq; using System.Text; -using Roslyn.Scripting.CSharp; namespace ScriptCs.Contracts { diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index e410c747..295af396 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -9,14 +9,6 @@ ..\..\ - - True - ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll - - - True - ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll - @@ -38,9 +30,6 @@ - - - \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index b0b698f7..2506ebd6 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.ComponentModel.Composition; -using Roslyn.Scripting; +using System.Threading.Tasks; +using ScriptCs.Contracts; namespace ScriptCs { @@ -8,13 +10,8 @@ namespace ScriptCs public interface IScriptEngine { string BaseDirectory { get; set; } - - void AddReference(string assemblyDisplayNameOrPath); + IScriptHostFactory ScriptHostFactory { get; set; } - ISession CreateSession(THostObject hostObject) where THostObject : class; - - ISession CreateSession(object hostObject, Type hostObjectType = null); - - ISession CreateSession(); + void Execute(string code, IEnumerable references, IEnumerable scriptPacks); } } diff --git a/src/ScriptCs.Core/ISession.cs b/src/ScriptCs.Core/ISession.cs deleted file mode 100644 index 69b8f165..00000000 --- a/src/ScriptCs.Core/ISession.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ScriptCs -{ - public interface ISession - { - object Execute(string code); - void AddReference(string assemblyDisplayNameOrPath); - void ImportNamespace(string @namespace); - } -} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 547cdf31..6f4d5cba 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -13,14 +13,6 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll - - True - ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll - - - True - ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll - @@ -47,7 +39,6 @@ - @@ -62,9 +53,6 @@ - - - diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 1339d8e8..1cdf6403 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,5 +1,4 @@ using System; -using Roslyn.Scripting.CSharp; using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; @@ -24,31 +23,28 @@ public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor } public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) : - this(fileSystem, filePreProcessor, scriptEngine, new ScriptHostFactory()) - { - - } + this(fileSystem, filePreProcessor, scriptEngine, new ScriptHostFactory()) { } public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) { - _scriptEngine.AddReference("System"); - _scriptEngine.AddReference("System.Core"); - var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); + var files = PrepareBinFolder(paths, bin); + + var references = new List(); + references.Add("System"); + references.Add("System.Core"); + references.AddRange(files); _scriptEngine.BaseDirectory = bin; + _scriptEngine.ScriptHostFactory = _scriptHostFactory; - var files = PrepareBinFolder(paths, bin); - var contexts = GetContexts(scriptPacks); - var host = _scriptHostFactory.CreateScriptHost(contexts); - var session = _scriptEngine.CreateSession(host); - AddReferences(files, session); - var scriptPackSession = new ScriptPackSession(session); - InitializeScriptPacks(scriptPacks, scriptPackSession); var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); - var csx = _filePreProcessor.ProcessFile(path); - session.Execute(csx); - TerminateScriptPacks(scriptPacks); + var code = _filePreProcessor.ProcessFile(path); + + _scriptEngine.Execute( + code: code, + references: references, + scriptPacks: scriptPacks); } private IEnumerable PrepareBinFolder(IEnumerable paths, string bin) @@ -70,38 +66,5 @@ private IEnumerable PrepareBinFolder(IEnumerable paths, string b return files; } - - private void AddReferences(IEnumerable files, ISession session) - { - foreach (var file in files) - { - session.AddReference(file); - } - } - - private IEnumerable GetContexts(IEnumerable scriptPacks) - { - foreach (var pack in scriptPacks) - { - yield return pack.GetContext(); - } - } - - private void InitializeScriptPacks(IEnumerable scriptPacks, IScriptPackSession session) - { - foreach (var pack in scriptPacks) - { - pack.Initialize(session); - } - } - - private void TerminateScriptPacks(IEnumerable scriptPacks) - { - foreach (var pack in scriptPacks) - { - pack.Terminate(); - } - } - } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs deleted file mode 100644 index e928c8e9..00000000 --- a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Roslyn.Scripting; -using Roslyn.Scripting.CSharp; - -namespace ScriptCs.Wrappers -{ - internal class ScriptEngineWrapper : IScriptEngine - { - private ScriptEngine scriptEngine; - - public ScriptEngineWrapper() - { - this.scriptEngine = new ScriptEngine(); - } - - public string BaseDirectory - { - get - { - return this.scriptEngine.BaseDirectory; - } - - set - { - this.scriptEngine.BaseDirectory = value; - } - } - - public void AddReference(string assemblyDisplayNameOrPath) - { - this.scriptEngine.AddReference(assemblyDisplayNameOrPath); - } - - public ISession CreateSession() - { - return new SessionWrapper(this.scriptEngine.CreateSession()); - } - - public ISession CreateSession(THostObject hostObject) where THostObject : class - { - return new SessionWrapper(this.scriptEngine.CreateSession(hostObject)); - } - - public ISession CreateSession(object hostObject, System.Type hostObjectType = null) - { - return new SessionWrapper(this.scriptEngine.CreateSession(hostObject, hostObjectType)); - } - } -} \ No newline at end of file diff --git a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs b/src/ScriptCs.Core/Wrappers/SessionWrapper.cs deleted file mode 100644 index 23a09331..00000000 --- a/src/ScriptCs.Core/Wrappers/SessionWrapper.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Roslyn.Scripting; - -namespace ScriptCs.Wrappers -{ - public class SessionWrapper : ISession - { - private Session _session; - - public SessionWrapper(Session session) - { - this._session = session; - } - - public object Execute(string code) - { - return this._session.Execute(code); - } - - public void AddReference(string assemblyDisplayNameOrPath) - { - this._session.AddReference(assemblyDisplayNameOrPath); - } - - public void ImportNamespace(string @namespace) - { - this._session.ImportNamespace(@namespace); - } - } -} diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index e0e22c31..6407750a 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -1,6 +1,4 @@  - - \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/Properties/AssemblyInfo.cs b/src/ScriptCs.Engine.Roslyn/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..275c7db4 --- /dev/null +++ b/src/ScriptCs.Engine.Roslyn/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ScriptCs.Engine.Roslyn")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ScriptCs.Engine.Roslyn")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0783d2c9-c21b-4281-a195-f0f83fc4936f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs new file mode 100644 index 00000000..a95aa13a --- /dev/null +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Roslyn.Scripting.CSharp; +using ScriptCs.Contracts; + +namespace ScriptCs.Engine.Roslyn +{ + public class RoslynScriptEngine : IScriptEngine + { + private readonly ScriptEngine _scriptEngine; + + public RoslynScriptEngine() + { + _scriptEngine = new ScriptEngine(); + } + + public string BaseDirectory + { + get { return _scriptEngine.BaseDirectory; } + set { _scriptEngine.BaseDirectory = value; } + } + + public IScriptHostFactory ScriptHostFactory { get; set; } + + public void Execute(string code, IEnumerable references, IEnumerable scriptPacks) + { + var contexts = scriptPacks.Select(x => x.GetContext()); + var host = ScriptHostFactory.CreateScriptHost(contexts); + + var session = _scriptEngine.CreateSession(host); + + foreach (var reference in references) + session.AddReference(reference); + + var scriptPackSession = new RoslynScriptPackSession(session); + + foreach (var pack in scriptPacks) + pack.Initialize(scriptPackSession); + + session.Execute(code); + + foreach (var pack in scriptPacks) + pack.Terminate(); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptPackSession.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptPackSession.cs similarity index 56% rename from src/ScriptCs.Core/ScriptPackSession.cs rename to src/ScriptCs.Engine.Roslyn/RoslynScriptPackSession.cs index 4cd80fdc..837b4502 100644 --- a/src/ScriptCs.Core/ScriptPackSession.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptPackSession.cs @@ -1,17 +1,15 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Roslyn.Scripting; using ScriptCs.Contracts; -namespace ScriptCs +namespace ScriptCs.Engine.Roslyn { - public class ScriptPackSession : IScriptPackSession + public class RoslynScriptPackSession : IScriptPackSession { - private readonly ISession _session; + private readonly Session _session; - public ScriptPackSession(ISession session) + internal RoslynScriptPackSession(Session session) { _session = session; } @@ -23,7 +21,7 @@ public void AddReference(string assemblyDisplayNameOrPath) public void ImportNamespace(string ns) { - + _session.ImportNamespace(ns); } } } diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj new file mode 100644 index 00000000..097ebf10 --- /dev/null +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -0,0 +1,76 @@ + + + + + Debug + AnyCPU + {E79EC231-E27D-4057-91C9-2D001A3A8C3B} + Library + Properties + ScriptCs.Engine.Roslyn + ScriptCs.Engine.Roslyn + v4.5 + 512 + ..\..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + + + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + + + + + + + + + + + + + + + + + + + + {6049e205-8b5f-4080-b023-70600e51fd64} + ScriptCs.Contracts + + + {e590e710-e159-48e6-a3e6-1a83d3fe732c} + ScriptCs.Core + + + + + + \ No newline at end of file diff --git a/src/ScriptCs.Contracts/packages.config b/src/ScriptCs.Engine.Roslyn/packages.config similarity index 100% rename from src/ScriptCs.Contracts/packages.config rename to src/ScriptCs.Engine.Roslyn/packages.config diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 5b6e69ed..cf72a497 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,8 +1,7 @@ using System; -using System.Collections.Generic; using System.ComponentModel.Composition.Hosting; -using System.IO; using System.Linq; +using ScriptCs.Engine.Roslyn; using ScriptCs.Exceptions; using ScriptCs.Package; @@ -49,6 +48,7 @@ private static CompositionContainer ConfigureMef() var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly)); catalog.Catalogs.Add(new AssemblyCatalog(typeof(ScriptExecutor).Assembly)); + catalog.Catalogs.Add(new AssemblyCatalog(typeof(RoslynScriptEngine).Assembly)); catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory,"*.pack.dll")); return new CompositionContainer(catalog); } diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 4c6fe27e..09849fed 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -39,6 +39,10 @@ {e590e710-e159-48e6-a3e6-1a83d3fe732c} ScriptCs.Core + + {e79ec231-e27d-4057-91c9-2d001a3a8c3b} + ScriptCs.Engine.Roslyn + diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index f7d6c204..dece863e 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; using Moq; -using ScriptCs; using ScriptCs.Contracts; using Should; using Xunit; @@ -24,14 +24,9 @@ private static ScriptExecutor CreateScriptExecutor( if (scriptEngine == null) { - var mockSession = new Mock(); - mockSession.Setup(s => s.AddReference(It.IsAny())); - mockSession.Setup(s => s.Execute(It.IsAny())).Returns(new object()); - scriptEngine = new Mock(); scriptEngine.SetupProperty(e => e.BaseDirectory); - scriptEngine.Setup(e => e.CreateSession()).Returns(mockSession.Object); - scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(mockSession.Object); + scriptEngine.SetupProperty(e => e.ScriptHostFactory); } if (scriptHostFactory == null) @@ -78,44 +73,12 @@ public void DoNotChangePathIfAbsolute() preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } - [Fact] - public void ShouldAddSystemAndSystemCoreReferencesToEngine() - { - // arrange - var fileSystem = new Mock(); - var scriptEngine = new Mock(); - var session = new Mock(); - - scriptEngine.Setup(e => e.AddReference("System")).Verifiable(); - scriptEngine.Setup(e => e.AddReference("System.Core")).Verifiable(); - scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); - - var currentDirectory = @"C:\"; - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); - - var scriptName = "script.csx"; - var paths = new string[0]; - IEnumerable recipes = Enumerable.Empty(); - - // act - scriptExecutor.Execute(scriptName, paths, recipes); - - // assert - scriptEngine.Verify(e => e.AddReference("System"), Times.Once()); - scriptEngine.Verify(e => e.AddReference("System.Core"), Times.Once()); - } - [Fact] public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() { // arrange var scriptEngine = new Mock(); var fileSystem = new Mock(); - var session = new Mock(); - scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); @@ -141,11 +104,7 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() public void ShouldCreateCurrentDirectoryIfItDoesNotExist() { // arrange - var scriptEngine = new Mock(); var fileSystem = new Mock(); - var session = new Mock(); - - scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); @@ -156,7 +115,7 @@ public void ShouldCreateCurrentDirectoryIfItDoesNotExist() fileSystem.Setup(fs => fs.DirectoryExists(binDirectory)).Returns(false).Verifiable(); fileSystem.Setup(fs => fs.CreateDirectory(binDirectory)).Verifiable(); - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); + var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem); var scriptName = "script.csx"; var paths = new string[0]; @@ -171,20 +130,15 @@ public void ShouldCreateCurrentDirectoryIfItDoesNotExist() } [Fact] - public void ShouldExecuteScriptReturnedFromFileProcessorInSessionWhenExecuteIsInvoked() + public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked() { // arrange var scriptEngine = new Mock(); var preProcessor = new Mock(); var fileSystem = new Mock(); - var session = new Mock(); string code = Guid.NewGuid().ToString(); - scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); - - session.Setup(s => s.Execute(code)).Returns(null).Verifiable(); - var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); @@ -199,94 +153,14 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInSessionWhenExecuteIsIn IEnumerable recipes = Enumerable.Empty(); preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(code).Verifiable(); + scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), recipes)); // act scriptExecutor.Execute(scriptName, paths, recipes); // assert preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); - session.Verify(s => s.Execute(code), Times.Once()); - } - - [Fact] - public void ShouldInitializeScriptPacks() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.Initialize(It.IsAny())); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - - executor.Execute("script.csx", Enumerable.Empty(), new List { scriptPack1.Object }); - scriptPack1.Verify(p => p.Initialize(It.IsAny())); - } - - [Fact] - public void ShouldCreateScriptHostWithContexts() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); - - var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny>())).Returns((IEnumerable c) => new ScriptHost(c)); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptHostFactory: scriptHostFactory); - - var scriptPack = new Mock(); - var context = new Mock().Object; - - scriptPack.Setup(p => p.GetContext()).Returns(context); - - executor.Execute("script.csx", Enumerable.Empty(), new List { scriptPack.Object }); - scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); - } - - [Fact] - public void ShouldCreateSessionWithScriptHost() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); - - var engine = new Mock(); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - - engine.Setup(e => e.CreateSession(It.IsAny())).Returns(new Mock().Object); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); - engine.Verify(e=>e.CreateSession(It.IsAny())); - } - - [Fact] - public void ShouldTerminateScriptPacksWhenScriptFinishes() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - - executor.Execute("script.csx", Enumerable.Empty(), new List { scriptPack1.Object }); - scriptPack1.Verify(p => p.Terminate()); + scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), recipes), Times.Once()); } [Fact] @@ -360,11 +234,7 @@ public void ShouldAddReferenceToEachDestinationFile() { // arrange var fileSystem = new Mock(); - var scriptEngine = new Mock(); - var session = new Mock(); - - scriptEngine.Setup(e => e.CreateSession(It.IsAny())).Returns(session.Object); var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); @@ -384,19 +254,15 @@ public void ShouldAddReferenceToEachDestinationFile() fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); - session.Setup(e => e.AddReference(destinationFilePath1)).Verifiable(); - session.Setup(e => e.AddReference(destinationFilePath2)).Verifiable(); - session.Setup(e => e.AddReference(destinationFilePath3)).Verifiable(); - session.Setup(e => e.AddReference(destinationFilePath4)).Verifiable(); + var destPaths = new string[] { "System", "System.Core", destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; + + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny>())); // act scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); // assert - session.Verify(e => e.AddReference(destinationFilePath1), Times.Once()); - session.Verify(e => e.AddReference(destinationFilePath2), Times.Once()); - session.Verify(e => e.AddReference(destinationFilePath3), Times.Once()); - session.Verify(e => e.AddReference(destinationFilePath4), Times.Once()); + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny>()), Times.Once()); } } } diff --git a/test/ScriptCs.Engine.Roslyn.Tests/Properties/AssemblyInfo.cs b/test/ScriptCs.Engine.Roslyn.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..bdf4591f --- /dev/null +++ b/test/ScriptCs.Engine.Roslyn.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ScriptCs.Engine.Roslyn")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ScriptCs.Engine.Roslyn")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("16063b38-8d89-4cec-abd2-45102e1905df")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs new file mode 100644 index 00000000..5adbb903 --- /dev/null +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Moq; +using ScriptCs.Contracts; +using ScriptCs.Engine.Roslyn; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class RoslynScriptEngineTests + { + private static RoslynScriptEngine CreateScriptEngine( + Mock scriptHostFactory = null) + { + scriptHostFactory = scriptHostFactory ?? new Mock(); + + return new RoslynScriptEngine { + ScriptHostFactory = scriptHostFactory.Object + }; + } + + public class TheExecuteMethod + { + [Fact] + public void ShouldInitializeScriptPacks() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + + var code = "var a = 0;"; + var engine = CreateScriptEngine(); + + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + + engine.Execute(code, Enumerable.Empty(), new List { scriptPack1.Object }); + scriptPack1.Verify(p => p.Initialize(It.IsAny())); + } + + [Fact] + public void ShouldCreateScriptHostWithContexts() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny>())).Returns((IEnumerable c) => new ScriptHost(c)); + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + + var scriptPack = new Mock(); + var context = new Mock().Object; + + scriptPack.Setup(p => p.GetContext()).Returns(context); + + engine.Execute("script.csx", Enumerable.Empty(), new List { scriptPack.Object }); + scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); + } + + [Fact] + public void ShouldTerminateScriptPacksWhenScriptFinishes() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var engine = CreateScriptEngine(); + + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + + engine.Execute("script.csx", Enumerable.Empty(), new List { scriptPack1.Object }); + scriptPack1.Verify(p => p.Terminate()); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj new file mode 100644 index 00000000..0434bb7c --- /dev/null +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj @@ -0,0 +1,88 @@ + + + + + Debug + AnyCPU + {28D11DE5-9F98-4E0A-8CCC-9CDC19110451} + Library + Properties + ScriptCs.Tests + ScriptCs.Engine.Roslyn.Tests + v4.5 + 512 + ..\..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll + + + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + + + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + + + ..\..\packages\Should.1.1.12.0\lib\Should.dll + + + + + + + + + + ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + + + + + + + + + + + {6049e205-8b5f-4080-b023-70600e51fd64} + ScriptCs.Contracts + + + {e590e710-e159-48e6-a3e6-1a83d3fe732c} + ScriptCs.Core + + + {e79ec231-e27d-4057-91c9-2d001a3a8c3b} + ScriptCs.Engine.Roslyn + + + + + + \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/packages.config b/test/ScriptCs.Engine.Roslyn.Tests/packages.config new file mode 100644 index 00000000..5a4e8724 --- /dev/null +++ b/test/ScriptCs.Engine.Roslyn.Tests/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From a4dfdb36afd240c851ffd458217f098232774789 Mon Sep 17 00:00:00 2001 From: Lodewijk Sioen Date: Mon, 11 Mar 2013 20:18:51 +0100 Subject: [PATCH 0062/1224] Added Icon for executable --- common/Icon.ico | Bin 0 -> 99678 bytes src/ScriptCs/ScriptCs.csproj | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 common/Icon.ico diff --git a/common/Icon.ico b/common/Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d946fa05f82911c79ac074a670e1da052097ae77 GIT binary patch literal 99678 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 T7|6#!J_hnJkdJ}C7zX}7QW`FK literal 0 HcmV?d00001 diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 4c6fe27e..2627498a 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -7,6 +7,9 @@ ScriptCs scriptcs + + ..\..\common\Icon.ico + @@ -40,6 +43,11 @@ ScriptCs.Core + + + Properties\Icon.ico + + \ No newline at end of file From 9ae37d4079af73be5c66e10c2106a9c11e1f3ef6 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 11 Mar 2013 15:31:06 -0700 Subject: [PATCH 0063/1224] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f517e135..d28d93e6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Why should you care? Write C# apps with a text editor, nuget and the power of Rosyln! -**Note**: *Rosyln is a pre-release CTP and currently an unsupported technology. As such there may be changes in Roslyn itself that could impact this project. Please bear that in mind when using scriptcs* +**Note**: *Roslyn is a pre-release CTP and currently an unsupported technology. As such there may be changes in Roslyn itself that could impact this project. Please bear that in mind when using scriptcs* * More on why I developed this [here] (http://codebetter.com/glennblock/2013/02/28/scriptcs-living-on-the-edge-in-c-without-a-project-on-the-wings-of-roslyn-and-nuget/) * Check out our goals and rodmap [here] (https://github.com/scriptcs/scriptcs/wiki/Project-goals-and-roadmap) From ecf66254bc8489a718059bc109b34ec25bf80d3a Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 11 Mar 2013 15:31:27 -0700 Subject: [PATCH 0064/1224] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d28d93e6..324dcd6f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # scriptcs ## Why should you care? -Write C# apps with a text editor, nuget and the power of Rosyln! +Write C# apps with a text editor, nuget and the power of Roslyn! **Note**: *Roslyn is a pre-release CTP and currently an unsupported technology. As such there may be changes in Roslyn itself that could impact this project. Please bear that in mind when using scriptcs* From 6eae4bf4f1a1eebac5a84690b1570d90d0bdde1b Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 11 Mar 2013 18:57:38 -0400 Subject: [PATCH 0065/1224] Add missing content to common assembly info files --- common/CommonAssemblyInfo.cs | 15 +++++++++++++++ common/CommonVersionInfo.cs | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/common/CommonAssemblyInfo.cs b/common/CommonAssemblyInfo.cs index e69de29b..b78de3c3 100644 --- a/common/CommonAssemblyInfo.cs +++ b/common/CommonAssemblyInfo.cs @@ -0,0 +1,15 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +#if DEBUG +[assembly: AssemblyConfiguration("Debug")] +#else +[assembly: AssemblyConfiguration("Release")] +#endif + +[assembly: AssemblyProduct("scriptcs")] +[assembly: AssemblyCopyright("Copyright 2013 Glenn Block, Justin Rusbatch, Filip Wojcieszyn")] + +[assembly: ComVisible(false)] +[assembly: CLSCompliant(false)] \ No newline at end of file diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index e69de29b..ce7aeb47 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -0,0 +1,5 @@ +using System.Reflection; + +[assembly: AssemblyVersion("0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] +[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file From 83ec508f27777cf8342e92869c07f3129f1a22b7 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 11 Mar 2013 18:57:58 -0400 Subject: [PATCH 0066/1224] Add a description to the ScriptCs.Core assembly --- src/ScriptCs.Core/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Properties/AssemblyInfo.cs b/src/ScriptCs.Core/Properties/AssemblyInfo.cs index f96afe0e..12e75063 100644 --- a/src/ScriptCs.Core/Properties/AssemblyInfo.cs +++ b/src/ScriptCs.Core/Properties/AssemblyInfo.cs @@ -2,6 +2,6 @@ using System.Runtime.InteropServices; [assembly: AssemblyTitle("ScriptCs.Core")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("ScriptCs.Core is the core framework assembly for scriptcs.")] [assembly: Guid("4c4ebd22-f4b0-47de-a417-f0a2a127508c")] From bc76729645769187b206de78446a6971b1995bc3 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 11 Mar 2013 18:59:06 -0400 Subject: [PATCH 0067/1224] Add a description for the command line application --- src/ScriptCs/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Properties/AssemblyInfo.cs b/src/ScriptCs/Properties/AssemblyInfo.cs index ffda0bf0..dfee66f6 100644 --- a/src/ScriptCs/Properties/AssemblyInfo.cs +++ b/src/ScriptCs/Properties/AssemblyInfo.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyTitle("scriptcs")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("scriptcs command line tool.")] [assembly: Guid("f624ee58-910a-4541-a46f-afcd3edca9df")] From 89a6e456e2df38183cb0a7376fd5c91bdd8d6159 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 11 Mar 2013 19:15:01 -0400 Subject: [PATCH 0068/1224] Add nuspec files for ScriptCs.Core and ScriptCs.Contracts --- .../Properties/ScriptCs.Contracts.nuspec | 13 +++++++++++++ src/ScriptCs.Contracts/ScriptCs.Contracts.csproj | 1 + src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec | 13 +++++++++++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + 4 files changed, 28 insertions(+) create mode 100644 src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec create mode 100644 src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec diff --git a/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec b/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec new file mode 100644 index 00000000..1b0de842 --- /dev/null +++ b/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec @@ -0,0 +1,13 @@ + + + + $id$ + $version$ + $author$ + http://www.apache.org/licenses/LICENSE-2.0.html + http://scriptcs.net + $description$ + + + + \ No newline at end of file diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index e410c747..5b17a2b2 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -40,6 +40,7 @@ + diff --git a/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec b/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec new file mode 100644 index 00000000..1b0de842 --- /dev/null +++ b/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec @@ -0,0 +1,13 @@ + + + + $id$ + $version$ + $author$ + http://www.apache.org/licenses/LICENSE-2.0.html + http://scriptcs.net + $description$ + + + + \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 987118cc..c252825b 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -79,6 +79,7 @@ + From 5b56d5e51037c831d9feb6bc7e8a423b89609121 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 11 Mar 2013 19:17:20 -0400 Subject: [PATCH 0069/1224] License URL should point to LICENSE.md in the master branch of the repository --- src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec | 2 +- src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec b/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec index 1b0de842..b95ab90a 100644 --- a/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec +++ b/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec @@ -4,7 +4,7 @@ $id$ $version$ $author$ - http://www.apache.org/licenses/LICENSE-2.0.html + https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md http://scriptcs.net $description$ diff --git a/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec b/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec index 1b0de842..b95ab90a 100644 --- a/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec +++ b/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec @@ -4,7 +4,7 @@ $id$ $version$ $author$ - http://www.apache.org/licenses/LICENSE-2.0.html + https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md http://scriptcs.net $description$ From 51e1c2bf71c1aa3a9f4d1a0e7a9c999fa2f4d70b Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 11 Mar 2013 19:46:31 -0400 Subject: [PATCH 0070/1224] Add missing Build.tasks file --- build/Build.tasks | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 build/Build.tasks diff --git a/build/Build.tasks b/build/Build.tasks new file mode 100644 index 00000000..3c48de20 --- /dev/null +++ b/build/Build.tasks @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + \ No newline at end of file From 57e6ee58bd5cd019990742ebeba2e7f1451f4ecb Mon Sep 17 00:00:00 2001 From: Brandon Stirnaman Date: Mon, 11 Mar 2013 21:29:44 -0500 Subject: [PATCH 0071/1224] Added FluentAutomation sample --- samples/fluentautomation/FluentAutomation.csx | 39 +++++++++++++++++++ samples/fluentautomation/README.md | 13 +++++++ samples/fluentautomation/TestKnockoutJS.csx | 26 +++++++++++++ samples/fluentautomation/packages.config | 8 ++++ 4 files changed, 86 insertions(+) create mode 100644 samples/fluentautomation/FluentAutomation.csx create mode 100644 samples/fluentautomation/README.md create mode 100644 samples/fluentautomation/TestKnockoutJS.csx create mode 100644 samples/fluentautomation/packages.config diff --git a/samples/fluentautomation/FluentAutomation.csx b/samples/fluentautomation/FluentAutomation.csx new file mode 100644 index 00000000..c1b7c5ef --- /dev/null +++ b/samples/fluentautomation/FluentAutomation.csx @@ -0,0 +1,39 @@ +using FluentAutomation; +using FluentAutomation.Interfaces; +using System; +using System.IO; +using System.Reflection; + +private static INativeActionSyntaxProvider I = null; + +public static void Bootstrap(string browserName) +{ + MethodInfo bootstrapMethod = null; + ParameterInfo[] bootstrapParams = null; + + MethodInfo[] methods = typeof(T).GetMethods(BindingFlags.Static | BindingFlags.Public); + foreach (var methodInfo in methods) + { + if (methodInfo.Name.Equals("Bootstrap")) + { + bootstrapMethod = methodInfo; + bootstrapParams = methodInfo.GetParameters(); + if (bootstrapParams.Length == 1) + { + break; + } + } + } + + var browserEnumValue = Enum.Parse(bootstrapParams[0].ParameterType, browserName); + bootstrapMethod.Invoke(null, new object[] { browserEnumValue }); + + I = new FluentTest().I; + + // hack to move drivers into bin so they can be located by Selenium (only prob on scriptcs atm) + foreach (var driver in Directory.GetFiles(Environment.CurrentDirectory, "*.exe")) + { + var newFileName = Path.Combine(Environment.CurrentDirectory, "bin", Path.GetFileName(driver)); + if (!File.Exists(newFileName)) File.Move(driver, newFileName); + } +} \ No newline at end of file diff --git a/samples/fluentautomation/README.md b/samples/fluentautomation/README.md new file mode 100644 index 00000000..0cf07cc5 --- /dev/null +++ b/samples/fluentautomation/README.md @@ -0,0 +1,13 @@ +*Instructions* + +- Install nuget somewhere in your path. +- Install scriptcs somewhere in your path. +- Download this gist to a folder. +- From that directory, run 'nuget install FluentAutomation.SeleniumWebDriver -o packages' +- Then run 'scriptcs TestKnockoutJS.csx' + +*Comments* + +This could be really really good from a testing standpoint. One file per test-case, with no extra bits necessary feels awesome. + +Also.. Don't forget to call I.Dispose() at the end of the script or the browser will just hang around after the test. I think we'll do some refactoring to make this a bit smarter in this context, as well as eliminate the need for the reflection in Bootstrap() in FluentAutomation.csx \ No newline at end of file diff --git a/samples/fluentautomation/TestKnockoutJS.csx b/samples/fluentautomation/TestKnockoutJS.csx new file mode 100644 index 00000000..d818b7a2 --- /dev/null +++ b/samples/fluentautomation/TestKnockoutJS.csx @@ -0,0 +1,26 @@ +#load "FluentAutomation.csx" + +Bootstrap("Chrome"); + +I.Open("http://knockoutjs.com/examples/cartEditor.html"); +I.Select("Motorcycles").From(".liveExample tr select:eq(0)"); // Select by value/text +I.Select(2).From(".liveExample tr select:eq(1)"); // Select by index +I.Enter(6).In(".liveExample td.quantity input:eq(0)"); +I.Expect.Text("$197.70").In(".liveExample tr span:eq(1)"); + +// add second product +I.Click(".liveExample button:eq(0)"); +I.Select(1).From(".liveExample tr select:eq(2)"); +I.Select(4).From(".liveExample tr select:eq(3)"); +I.Enter(8).In(".liveExample td.quantity input:eq(1)"); +I.Expect.Text("$788.64").In(".liveExample tr span:eq(3)"); + +// validate totals +I.Expect.Text("$986.34").In("p.grandTotal span"); + +// remove first product +I.Click(".liveExample a:eq(0)"); + +// validate new total +I.WaitUntil(() => I.Expect.Text("$788.64").In("p.grandTotal span")); +I.Dispose(); \ No newline at end of file diff --git a/samples/fluentautomation/packages.config b/samples/fluentautomation/packages.config new file mode 100644 index 00000000..46e0577d --- /dev/null +++ b/samples/fluentautomation/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From 4f9ddbab74b7be06479f3261dce001e91910c32b Mon Sep 17 00:00:00 2001 From: Brandon Stirnaman Date: Mon, 11 Mar 2013 21:40:47 -0500 Subject: [PATCH 0072/1224] Changed tabs to spaces --- samples/fluentautomation/FluentAutomation.csx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/fluentautomation/FluentAutomation.csx b/samples/fluentautomation/FluentAutomation.csx index c1b7c5ef..e392f0c7 100644 --- a/samples/fluentautomation/FluentAutomation.csx +++ b/samples/fluentautomation/FluentAutomation.csx @@ -28,12 +28,12 @@ public static void Bootstrap(string browserName) var browserEnumValue = Enum.Parse(bootstrapParams[0].ParameterType, browserName); bootstrapMethod.Invoke(null, new object[] { browserEnumValue }); - I = new FluentTest().I; + I = new FluentTest().I; - // hack to move drivers into bin so they can be located by Selenium (only prob on scriptcs atm) - foreach (var driver in Directory.GetFiles(Environment.CurrentDirectory, "*.exe")) - { - var newFileName = Path.Combine(Environment.CurrentDirectory, "bin", Path.GetFileName(driver)); - if (!File.Exists(newFileName)) File.Move(driver, newFileName); - } -} \ No newline at end of file + // hack to move drivers into bin so they can be located by Selenium (only prob on scriptcs atm) + foreach (var driver in Directory.GetFiles(Environment.CurrentDirectory, "*.exe")) + { + var newFileName = Path.Combine(Environment.CurrentDirectory, "bin", Path.GetFileName(driver)); + if (!File.Exists(newFileName)) File.Move(driver, newFileName); + } +} From b678ff0f39fcd8b275a174bf106a4f2cd3bf54c5 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Tue, 12 Mar 2013 00:21:49 -0300 Subject: [PATCH 0073/1224] # Updated code base to get rid of MEF attributes and use RegistrationBuilder --- src/ScriptCs.Contracts/IScriptPack.cs | 10 +--- src/ScriptCs.Core/DebugFilePreProcessor.cs | 3 -- src/ScriptCs.Core/DebugScriptExecutor.cs | 4 +- src/ScriptCs.Core/FilePreProcessor.cs | 2 - src/ScriptCs.Core/ICompiledDllDebugger.cs | 1 - src/ScriptCs.Core/IFileSystem.cs | 1 - src/ScriptCs.Core/IPackageAssemblyResolver.cs | 1 - src/ScriptCs.Core/IScriptEngine.cs | 1 - src/ScriptCs.Core/IScriptHostFactory.cs | 8 +-- .../Package/IPackageContainer.cs | 2 - src/ScriptCs.Core/PackageAssemblyResolver.cs | 1 - src/ScriptCs.Core/ScriptExecutor.cs | 4 +- src/ScriptCs.Core/ScriptPackResolver.cs | 6 +-- .../Wrappers/ScriptEngineWrapper.cs | 4 +- src/ScriptCs/Program.cs | 54 ++++++++++++++++--- src/ScriptCs/ScriptCs.csproj | 2 + 16 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/ScriptCs.Contracts/IScriptPack.cs b/src/ScriptCs.Contracts/IScriptPack.cs index 0174b0e6..ff186662 100644 --- a/src/ScriptCs.Contracts/IScriptPack.cs +++ b/src/ScriptCs.Contracts/IScriptPack.cs @@ -1,13 +1,5 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using Roslyn.Scripting.CSharp; - -namespace ScriptCs.Contracts +namespace ScriptCs.Contracts { - [InheritedExport] public interface IScriptPack { void Initialize(IScriptPackSession session); diff --git a/src/ScriptCs.Core/DebugFilePreProcessor.cs b/src/ScriptCs.Core/DebugFilePreProcessor.cs index cafe47cd..7a3ac7b3 100644 --- a/src/ScriptCs.Core/DebugFilePreProcessor.cs +++ b/src/ScriptCs.Core/DebugFilePreProcessor.cs @@ -1,15 +1,12 @@ using System.Collections.Generic; -using System.ComponentModel.Composition; using System.Linq; namespace ScriptCs { - [Export(Constants.DebugContractName, typeof(IFilePreProcessor))] public class DebugFilePreProcessor : FilePreProcessor { private const string SystemDiagnosticsUsing = "using System.Diagnostics;"; - [ImportingConstructor] public DebugFilePreProcessor(IFileSystem fileSystem) : base(fileSystem) { diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index ce9b00c1..659a048a 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -4,15 +4,13 @@ namespace ScriptCs { - [Export(Constants.DebugContractName, typeof(IScriptExecutor))] public class DebugScriptExecutor : ScriptExecutor { private readonly ICompiledDllDebugger _compiledDllDebugger; - [ImportingConstructor] public DebugScriptExecutor( IFileSystem fileSystem, - [Import(Constants.DebugContractName)]IFilePreProcessor filePreProcessor, + IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ICompiledDllDebugger compiledDllDebugger, IScriptHostFactory scriptHostFactory) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 4d99ee98..9b964033 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -5,7 +5,6 @@ namespace ScriptCs { - [Export(Constants.RunContractName, typeof(IFilePreProcessor))] public class FilePreProcessor : IFilePreProcessor { private const string LoadString = "#load "; @@ -13,7 +12,6 @@ public class FilePreProcessor : IFilePreProcessor protected readonly IFileSystem _fileSystem; - [ImportingConstructor] public FilePreProcessor(IFileSystem fileSystem) { _fileSystem = fileSystem; diff --git a/src/ScriptCs.Core/ICompiledDllDebugger.cs b/src/ScriptCs.Core/ICompiledDllDebugger.cs index f944d5ec..d530088e 100644 --- a/src/ScriptCs.Core/ICompiledDllDebugger.cs +++ b/src/ScriptCs.Core/ICompiledDllDebugger.cs @@ -2,7 +2,6 @@ namespace ScriptCs { - [InheritedExport] public interface ICompiledDllDebugger { void Run(string dllPath, ISession session); diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 820e488f..4a8ef01b 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -5,7 +5,6 @@ namespace ScriptCs { - [InheritedExport] public interface IFileSystem { IEnumerable EnumerateFiles(string dir, string search); diff --git a/src/ScriptCs.Core/IPackageAssemblyResolver.cs b/src/ScriptCs.Core/IPackageAssemblyResolver.cs index ac5f39a2..eff0d5f6 100644 --- a/src/ScriptCs.Core/IPackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/IPackageAssemblyResolver.cs @@ -3,7 +3,6 @@ namespace ScriptCs { - [InheritedExport] public interface IPackageAssemblyResolver { IEnumerable GetAssemblyNames(string workingDirectory); diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index b0b698f7..c06a088f 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -4,7 +4,6 @@ namespace ScriptCs { - [InheritedExport] public interface IScriptEngine { string BaseDirectory { get; set; } diff --git a/src/ScriptCs.Core/IScriptHostFactory.cs b/src/ScriptCs.Core/IScriptHostFactory.cs index 63c0787c..55599532 100644 --- a/src/ScriptCs.Core/IScriptHostFactory.cs +++ b/src/ScriptCs.Core/IScriptHostFactory.cs @@ -1,14 +1,8 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; using ScriptCs.Contracts; namespace ScriptCs { - [InheritedExport] public interface IScriptHostFactory { ScriptHost CreateScriptHost(IEnumerable contexts); diff --git a/src/ScriptCs.Core/Package/IPackageContainer.cs b/src/ScriptCs.Core/Package/IPackageContainer.cs index 77127b12..56f3f673 100644 --- a/src/ScriptCs.Core/Package/IPackageContainer.cs +++ b/src/ScriptCs.Core/Package/IPackageContainer.cs @@ -1,9 +1,7 @@ using System.Collections.Generic; -using System.ComponentModel.Composition; namespace ScriptCs.Package { - [InheritedExport] public interface IPackageContainer { IEnumerable FindReferences(string path); diff --git a/src/ScriptCs.Core/PackageAssemblyResolver.cs b/src/ScriptCs.Core/PackageAssemblyResolver.cs index 951be349..5925a79e 100644 --- a/src/ScriptCs.Core/PackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/PackageAssemblyResolver.cs @@ -12,7 +12,6 @@ public class PackageAssemblyResolver : IPackageAssemblyResolver private readonly IFileSystem _fileSystem; private readonly IPackageContainer _packageContainer; - [ImportingConstructor] public PackageAssemblyResolver(IFileSystem fileSystem, IPackageContainer packageContainer) { _fileSystem = fileSystem; diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index b6a53ac8..1eb22659 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -5,7 +5,6 @@ namespace ScriptCs { - [Export(Constants.RunContractName, typeof(IScriptExecutor))] public class ScriptExecutor : IScriptExecutor { protected readonly IFileSystem _fileSystem; @@ -13,8 +12,7 @@ public class ScriptExecutor : IScriptExecutor private readonly IScriptEngine _scriptEngine; private readonly IScriptHostFactory _scriptHostFactory; - [ImportingConstructor] - public ScriptExecutor(IFileSystem fileSystem, [Import(Constants.RunContractName)]IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) + public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) { _fileSystem = fileSystem; _filePreProcessor = filePreProcessor; diff --git a/src/ScriptCs.Core/ScriptPackResolver.cs b/src/ScriptCs.Core/ScriptPackResolver.cs index e33fa5c3..224aa1b7 100644 --- a/src/ScriptCs.Core/ScriptPackResolver.cs +++ b/src/ScriptCs.Core/ScriptPackResolver.cs @@ -1,8 +1,6 @@ -using ScriptCs.Contracts; -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.Composition.Hosting; -using System.Linq; +using ScriptCs.Contracts; namespace ScriptCs { diff --git a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs index b98afd72..29752be1 100644 --- a/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs +++ b/src/ScriptCs.Core/Wrappers/ScriptEngineWrapper.cs @@ -1,5 +1,4 @@ -using System.ComponentModel.Composition; -using Roslyn.Scripting; +using Roslyn.Scripting; using Roslyn.Scripting.CSharp; namespace ScriptCs.Wrappers @@ -8,7 +7,6 @@ internal class ScriptEngineWrapper : IScriptEngine { private CommonScriptEngine _scriptEngine; - [ImportingConstructor] public ScriptEngineWrapper() { _scriptEngine = new ScriptEngine(); diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index b8ac4a90..228c4599 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -5,6 +5,12 @@ namespace ScriptCs { + using System.ComponentModel.Composition.Registration; + using System.Reflection; + + using ScriptCs.Contracts; + using ScriptCs.Package; + internal class Program { private static void Main(string[] args) @@ -33,12 +39,10 @@ private static void Main(string[] args) } } - var contractsMode = debug ? Constants.DebugContractName : Constants.RunContractName; - - var container = ConfigureMef(); + var container = ConfigureMef(debug); var fileSystem = container.GetExportedValue(); var resolver = container.GetExportedValue(); - var executor = container.GetExportedValue(contractsMode); + var executor = container.GetExportedValue(); var scriptPackManager = new ScriptPackResolver(container); try @@ -63,13 +67,47 @@ private static void WriteUsageMessage() Console.WriteLine("Usage:\r\n\r\nscriptcs csxFile [-debug]\r\n"); } - private static CompositionContainer ConfigureMef() + private static CompositionContainer ConfigureMef(bool debug) { + var conventions = SetupMefConventions(debug); + var catalog = new AggregateCatalog(); - catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly)); - catalog.Catalogs.Add(new AssemblyCatalog(typeof(ScriptExecutor).Assembly)); - catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory,"*.pack.dll")); + catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly, conventions)); + catalog.Catalogs.Add(new AssemblyCatalog(typeof(ScriptExecutor).Assembly, conventions)); + catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory, "*.pack.dll", conventions)); + return new CompositionContainer(catalog); } + + private static RegistrationBuilder SetupMefConventions(bool debug) + { + var conventions = new RegistrationBuilder(); + + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom() + .Export() + .SelectConstructor( + constructors => + constructors.First( + c => c.GetParameters().Length == constructors.Min(ctor => ctor.GetParameters().Length))); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + + if (debug) + { + conventions.ForType().Export(); + conventions.ForType().Export(); + } + else + { + conventions.ForType().Export(); + conventions.ForType().Export(); + } + + return conventions; + } } } \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 2627498a..f4b5c77a 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -13,7 +13,9 @@ + + From c02f6b48a4de5d10d4f19d7ef6c39880535d2590 Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Mon, 11 Mar 2013 23:23:51 -0400 Subject: [PATCH 0074/1224] refactored code to bring ScriptPackSession back into the core 1. We refactor ScriptPackSession so it is just a data bag with some methods. 2. That allows it to be easily passed to the engine which figures out how to apply it. 3. We move the initialize and terminate into ScriptCs.core. --- src/ScriptCs.Contracts/IScriptPackSession.cs | 7 +- src/ScriptCs.Core/IScriptEngine.cs | 19 ++--- src/ScriptCs.Core/ScriptCs.Core.csproj | 3 +- src/ScriptCs.Core/ScriptExecutor.cs | 20 +++-- src/ScriptCs.Core/ScriptPackSession.cs | 52 ++++++++++++ .../RoslynScriptEngine.cs | 18 +---- .../RoslynScriptPackSession.cs | 27 ------- .../ScriptCs.Engine.Roslyn.csproj | 1 - .../ScriptExecutorTests.cs | 80 +++++++++++++++++-- .../RoslynScriptEngineTests.cs | 59 +------------- 10 files changed, 158 insertions(+), 128 deletions(-) create mode 100644 src/ScriptCs.Core/ScriptPackSession.cs delete mode 100644 src/ScriptCs.Engine.Roslyn/RoslynScriptPackSession.cs diff --git a/src/ScriptCs.Contracts/IScriptPackSession.cs b/src/ScriptCs.Contracts/IScriptPackSession.cs index 8f74897f..a211234b 100644 --- a/src/ScriptCs.Contracts/IScriptPackSession.cs +++ b/src/ScriptCs.Contracts/IScriptPackSession.cs @@ -1,7 +1,12 @@ -namespace ScriptCs.Contracts +using System.Collections.Generic; + +namespace ScriptCs.Contracts { public interface IScriptPackSession { + List References { get; } + List Namespaces { get; } + void AddReference(string assemblyDisplayNameOrPath); void ImportNamespace(string @namespace); } diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index 2506ebd6..9127b3ac 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -1,17 +1,12 @@ -using System; using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Threading.Tasks; +using System.Linq; using ScriptCs.Contracts; namespace ScriptCs { - [InheritedExport] - public interface IScriptEngine - { - string BaseDirectory { get; set; } - IScriptHostFactory ScriptHostFactory { get; set; } - - void Execute(string code, IEnumerable references, IEnumerable scriptPacks); - } -} + public interface IScriptEngine + { + string BaseDirectory { get; set; } + void Execute(string code, IEnumerable references, IScriptPackSession scriptPackSession, object hostObject = null); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index d08efd20..d48e2817 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -38,9 +38,9 @@ + - @@ -56,6 +56,7 @@ + diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index abf3e563..7defa748 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; +using System.Linq; using ScriptCs.Contracts; namespace ScriptCs @@ -36,15 +37,20 @@ public void Execute(string script, IEnumerable paths, IEnumerable x.GetContext()); + var host = _scriptHostFactory.CreateScriptHost(contexts); + + using (var scriptPackSession = new ScriptPackSession(scriptPacks)) { + var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); + var code = _filePreProcessor.ProcessFile(path); - _scriptEngine.Execute( - code: code, - references: references, - scriptPacks: scriptPacks); + _scriptEngine.Execute( + code: code, + references: references, + scriptPackSession: scriptPackSession, + hostObject: host); + } } private IEnumerable PrepareBinFolder(IEnumerable paths, string bin) diff --git a/src/ScriptCs.Core/ScriptPackSession.cs b/src/ScriptCs.Core/ScriptPackSession.cs new file mode 100644 index 00000000..978f0805 --- /dev/null +++ b/src/ScriptCs.Core/ScriptPackSession.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public class ScriptPackSession : IScriptPackSession, IDisposable + { + private readonly IEnumerable _scriptPacks; + + public ScriptPackSession(IEnumerable scriptPacks) + { + _scriptPacks = scriptPacks; + + References = new List(); + Namespaces = new List(); + + InitializePacks(); + } + + public List References { get; private set; } + public List Namespaces { get; private set; } + + public void Dispose() + { + TerminatePacks(); + } + + private void InitializePacks() + { + foreach (var s in _scriptPacks) + s.Initialize(this); + } + + private void TerminatePacks() + { + foreach (var s in _scriptPacks) + s.Terminate(); + } + + void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) + { + References.Add(assemblyDisplayNameOrPath); + } + + void IScriptPackSession.ImportNamespace(string @namespace) + { + Namespaces.Add(@namespace); + } + } +} diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ff549f88..8ede66fd 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -24,27 +24,17 @@ public string BaseDirectory set { _scriptEngine.BaseDirectory = value; } } - public IScriptHostFactory ScriptHostFactory { get; set; } - - public void Execute(string code, IEnumerable references, IEnumerable scriptPacks) + public void Execute(string code, IEnumerable references, IScriptPackSession scriptPackSession, object hostObject = null) { - var contexts = scriptPacks.Select(x => x.GetContext()); - var host = ScriptHostFactory.CreateScriptHost(contexts); - - var session = _scriptEngine.CreateSession(host); + var session = _scriptEngine.CreateSession(hostObject); foreach (var reference in references) session.AddReference(reference); - var scriptPackSession = new RoslynScriptPackSession(session); - - foreach (var pack in scriptPacks) - pack.Initialize(scriptPackSession); + foreach (var reference in scriptPackSession.References) + session.AddReference(reference); Execute(code, session); - - foreach (var pack in scriptPacks) - pack.Terminate(); } protected virtual void Execute(string code, Session session) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptPackSession.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptPackSession.cs deleted file mode 100644 index 837b4502..00000000 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptPackSession.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Linq; -using Roslyn.Scripting; -using ScriptCs.Contracts; - -namespace ScriptCs.Engine.Roslyn -{ - public class RoslynScriptPackSession : IScriptPackSession - { - private readonly Session _session; - - internal RoslynScriptPackSession(Session session) - { - _session = session; - } - - public void AddReference(string assemblyDisplayNameOrPath) - { - _session.AddReference(assemblyDisplayNameOrPath); - } - - public void ImportNamespace(string ns) - { - _session.ImportNamespace(ns); - } - } -} diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 7153b372..2cfe65ad 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -51,7 +51,6 @@ - diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 5a2e6ebf..f508f17b 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -30,7 +30,6 @@ public static ScriptExecutor CreateScriptExecutor( { scriptEngine = new Mock(); scriptEngine.SetupProperty(e => e.BaseDirectory); - scriptEngine.SetupProperty(e => e.ScriptHostFactory); } if (scriptHostFactory == null) @@ -154,18 +153,18 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut var scriptName = "script.csx"; var paths = new string[0]; - IEnumerable recipes = Enumerable.Empty(); + var recipes = Enumerable.Empty(); preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(code).Verifiable(); - scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), recipes)); + scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny(), It.IsAny())); // act scriptExecutor.Execute(scriptName, paths, recipes); // assert preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); - - scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), recipes), Times.Once()); + + scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny(), It.IsAny()), Times.Once()); } @@ -263,13 +262,80 @@ public void ShouldAddReferenceToEachDestinationFile() var destPaths = new string[] { "System", "System.Core", destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; - scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny>())); + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny(), It.IsAny())); // act scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); // assert - scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny>()), Times.Once()); + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny(), It.IsAny()), Times.Once()); + } + + [Fact] + public void ShouldInitializeScriptPacks() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); + + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + + executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + + scriptPack1.Verify(p => p.Initialize(It.IsAny())); + } + + [Fact] + public void ShouldCreateScriptHostWithContexts() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny>())).Returns((IEnumerable c) => new ScriptHost(c)); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptHostFactory: scriptHostFactory); + + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + + executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + + scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); + } + + [Fact] + public void ShouldTerminateScriptPacksWhenScriptFinishes() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); + + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + scriptPack1.Setup(p => p.Terminate()); + + executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + + scriptPack1.Verify(p => p.Terminate()); } } } diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index f736c0e6..ab4c9a8a 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -15,69 +15,12 @@ private static RoslynScriptEngine CreateScriptEngine( { scriptHostFactory = scriptHostFactory ?? new Mock(); - return new RoslynScriptEngine { - ScriptHostFactory = scriptHostFactory.Object - }; + return new RoslynScriptEngine(); } public class TheExecuteMethod { - [Fact] - public void ShouldInitializeScriptPacks() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - var code = "var a = 0;"; - var engine = CreateScriptEngine(); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.Initialize(It.IsAny())); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - - engine.Execute(code, Enumerable.Empty(), new List { scriptPack1.Object }); - scriptPack1.Verify(p => p.Initialize(It.IsAny())); - } - - [Fact] - public void ShouldCreateScriptHostWithContexts() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - - var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny>())).Returns((IEnumerable c) => new ScriptHost(c)); - - var code = "var a = 0;"; - var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); - - var scriptPack = new Mock(); - var context = new Mock().Object; - - scriptPack.Setup(p => p.GetContext()).Returns(context); - - engine.Execute(code, Enumerable.Empty(), new List { scriptPack.Object }); - scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); - } - - [Fact] - public void ShouldTerminateScriptPacksWhenScriptFinishes() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - - var code = "var a = 0;"; - var engine = CreateScriptEngine(); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - - engine.Execute(code, Enumerable.Empty(), new List { scriptPack1.Object }); - scriptPack1.Verify(p => p.Terminate()); - } } } } \ No newline at end of file From e0acd20bc5e028310c53d915968137b53a6520bd Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Mon, 11 Mar 2013 23:26:46 -0400 Subject: [PATCH 0075/1224] added [InheritedExport] back onto IScriptEngine --- src/ScriptCs.Core/IScriptEngine.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index 9127b3ac..0312204d 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; +using System.ComponentModel.Composition; using System.Linq; using ScriptCs.Contracts; namespace ScriptCs { + [InheritedExport] public interface IScriptEngine { string BaseDirectory { get; set; } From 688c9a43d6fcb81ffc5641620ed306e0594ba1d0 Mon Sep 17 00:00:00 2001 From: Brandon Stirnaman Date: Mon, 11 Mar 2013 22:42:06 -0500 Subject: [PATCH 0076/1224] Changed the default browser to InternetExplorer --- samples/fluentautomation/TestKnockoutJS.csx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/fluentautomation/TestKnockoutJS.csx b/samples/fluentautomation/TestKnockoutJS.csx index d818b7a2..a2a54550 100644 --- a/samples/fluentautomation/TestKnockoutJS.csx +++ b/samples/fluentautomation/TestKnockoutJS.csx @@ -1,6 +1,6 @@ #load "FluentAutomation.csx" -Bootstrap("Chrome"); +Bootstrap("InternetExplorer"); I.Open("http://knockoutjs.com/examples/cartEditor.html"); I.Select("Motorcycles").From(".liveExample tr select:eq(0)"); // Select by value/text @@ -23,4 +23,4 @@ I.Click(".liveExample a:eq(0)"); // validate new total I.WaitUntil(() => I.Expect.Text("$788.64").In("p.grandTotal span")); -I.Dispose(); \ No newline at end of file +I.Dispose(); From 16cb5f55e3d58218ad3ec24d01c012f30718b92d Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Tue, 12 Mar 2013 00:44:04 -0300 Subject: [PATCH 0077/1224] # Removed namespaces that are no longer used --- src/ScriptCs.Core/DebugScriptExecutor.cs | 3 +-- src/ScriptCs.Core/FilePreProcessor.cs | 1 - src/ScriptCs.Core/ICompiledDllDebugger.cs | 4 +--- src/ScriptCs.Core/IFilePreProcessor.cs | 4 +--- src/ScriptCs.Core/IFileSystem.cs | 1 - src/ScriptCs.Core/IPackageAssemblyResolver.cs | 1 - src/ScriptCs.Core/IScriptEngine.cs | 2 -- src/ScriptCs.Core/PackageAssemblyResolver.cs | 1 - src/ScriptCs.Core/ScriptExecutor.cs | 1 - src/ScriptCs/Program.cs | 1 - 10 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index 659a048a..16feeaec 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -1,5 +1,4 @@ -using System.ComponentModel.Composition; -using System.IO; +using System.IO; using ScriptCs.Exceptions; namespace ScriptCs diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 9b964033..542c03e0 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; using System.Linq; namespace ScriptCs diff --git a/src/ScriptCs.Core/ICompiledDllDebugger.cs b/src/ScriptCs.Core/ICompiledDllDebugger.cs index d530088e..e71cc273 100644 --- a/src/ScriptCs.Core/ICompiledDllDebugger.cs +++ b/src/ScriptCs.Core/ICompiledDllDebugger.cs @@ -1,6 +1,4 @@ -using System.ComponentModel.Composition; - -namespace ScriptCs +namespace ScriptCs { public interface ICompiledDllDebugger { diff --git a/src/ScriptCs.Core/IFilePreProcessor.cs b/src/ScriptCs.Core/IFilePreProcessor.cs index 40130b45..1929da65 100644 --- a/src/ScriptCs.Core/IFilePreProcessor.cs +++ b/src/ScriptCs.Core/IFilePreProcessor.cs @@ -1,6 +1,4 @@ -using System.ComponentModel.Composition; - -namespace ScriptCs +namespace ScriptCs { public interface IFilePreProcessor { diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 4a8ef01b..ae3f122d 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; using System.IO; namespace ScriptCs diff --git a/src/ScriptCs.Core/IPackageAssemblyResolver.cs b/src/ScriptCs.Core/IPackageAssemblyResolver.cs index eff0d5f6..20e81578 100644 --- a/src/ScriptCs.Core/IPackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/IPackageAssemblyResolver.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.ComponentModel.Composition; namespace ScriptCs { diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index c06a088f..9f3b465c 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -1,6 +1,4 @@ using System; -using System.ComponentModel.Composition; -using Roslyn.Scripting; namespace ScriptCs { diff --git a/src/ScriptCs.Core/PackageAssemblyResolver.cs b/src/ScriptCs.Core/PackageAssemblyResolver.cs index 5925a79e..9fd05a4d 100644 --- a/src/ScriptCs.Core/PackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/PackageAssemblyResolver.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.ComponentModel.Composition; using System.IO; using System.Linq; using ScriptCs.Exceptions; diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 1eb22659..04dfd429 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.ComponentModel.Composition; using System.IO; using ScriptCs.Contracts; diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 228c4599..bc9d8c46 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -6,7 +6,6 @@ namespace ScriptCs { using System.ComponentModel.Composition.Registration; - using System.Reflection; using ScriptCs.Contracts; using ScriptCs.Package; From dfda07ee20b8597a58dbce098bfc6c8ec76c051d Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Tue, 12 Mar 2013 07:39:47 -0300 Subject: [PATCH 0078/1224] # Simplified code for IScriptEngine constructor convention. Thanks to @khellang for the code review. --- src/ScriptCs/Program.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index bc9d8c46..87f997cf 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -88,10 +88,7 @@ private static RegistrationBuilder SetupMefConventions(bool debug) conventions.ForTypesDerivedFrom().Export(); conventions.ForTypesDerivedFrom() .Export() - .SelectConstructor( - constructors => - constructors.First( - c => c.GetParameters().Length == constructors.Min(ctor => ctor.GetParameters().Length))); + .SelectConstructor(constructors => constructors.OrderBy(c => c.GetParameters().Length).First()); conventions.ForTypesDerivedFrom().Export(); conventions.ForTypesDerivedFrom().Export(); From 0e608d04823e2b6caf3ce51802ac090ac168f658 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 07:40:31 -0400 Subject: [PATCH 0079/1224] Add packaging targets to build script --- build/Build.proj | 25 +++++++++++++++++++++++-- build/ScriptCs.Version.props | 8 -------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/build/Build.proj b/build/Build.proj index 2dd60173..9b8a20bb 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -2,6 +2,9 @@ + + + Debug @@ -19,14 +22,25 @@ - + + + AssemblyVersion\("\d+\.\d+\.\d+"\) + AssemblyVersion("$(AssemblyVersion)") + + + AssemblyInformationalVersion\("\d+\.\d+\.\d+(-\w+\d*(-\d+)?)?"\) + AssemblyInformationalVersion("$(PackageVersion)") + + + + - + @@ -36,9 +50,16 @@ + + + + + + + \ No newline at end of file diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 5bc2a765..99075bdb 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -18,12 +18,4 @@ $(MajorVersion).$(MinorVersion).$(PatchVersion) $(PackageVersion)-$(BuildQuality) - \ No newline at end of file From b78537a3ee34180032708b00315a514f4f8a81f4 Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Tue, 12 Mar 2013 09:23:33 -0400 Subject: [PATCH 0080/1224] moved ScriptHostFactory into Roslyn since the script host is Roslyn specific --- src/ScriptCs.Contracts/IScriptPackSession.cs | 3 -- src/ScriptCs.Core/DebugScriptExecutor.cs | 4 +- src/ScriptCs.Core/IScriptEngine.cs | 2 +- src/ScriptCs.Core/IScriptHostFactory.cs | 16 ------- src/ScriptCs.Core/ScriptCs.Core.csproj | 3 -- src/ScriptCs.Core/ScriptExecutor.cs | 13 +----- src/ScriptCs.Core/ScriptPackSession.cs | 18 +++++--- .../IScriptHostFactory.cs | 13 ++++++ .../RoslynScriptDebuggerEngine.cs | 4 ++ .../RoslynScriptEngine.cs | 13 ++++-- .../ScriptCs.Engine.Roslyn.csproj | 3 ++ .../ScriptHost.cs | 4 +- .../ScriptHostFactory.cs | 4 +- .../ScriptExecutorTests.cs | 44 +++---------------- .../RoslynScriptEngineTests.cs | 25 ++++++++++- 15 files changed, 81 insertions(+), 88 deletions(-) delete mode 100644 src/ScriptCs.Core/IScriptHostFactory.cs create mode 100644 src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs rename src/{ScriptCs.Core => ScriptCs.Engine.Roslyn}/ScriptHost.cs (81%) rename src/{ScriptCs.Core => ScriptCs.Engine.Roslyn}/ScriptHostFactory.cs (81%) diff --git a/src/ScriptCs.Contracts/IScriptPackSession.cs b/src/ScriptCs.Contracts/IScriptPackSession.cs index a211234b..115211c3 100644 --- a/src/ScriptCs.Contracts/IScriptPackSession.cs +++ b/src/ScriptCs.Contracts/IScriptPackSession.cs @@ -4,9 +4,6 @@ namespace ScriptCs.Contracts { public interface IScriptPackSession { - List References { get; } - List Namespaces { get; } - void AddReference(string assemblyDisplayNameOrPath); void ImportNamespace(string @namespace); } diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index 2d75dbfb..d2e24528 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -6,7 +6,7 @@ namespace ScriptCs public class DebugScriptExecutor : ScriptExecutor { [ImportingConstructor] - public DebugScriptExecutor(IFileSystem fileSystem, [Import(Constants.DebugContractName)]IFilePreProcessor filePreProcessor, [Import(Constants.DebugContractName)]IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) - : base(fileSystem, filePreProcessor, scriptEngine, scriptHostFactory) { } + public DebugScriptExecutor(IFileSystem fileSystem, [Import(Constants.DebugContractName)]IFilePreProcessor filePreProcessor, [Import(Constants.DebugContractName)]IScriptEngine scriptEngine) + : base(fileSystem, filePreProcessor, scriptEngine) { } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index 0312204d..81754301 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -9,6 +9,6 @@ namespace ScriptCs public interface IScriptEngine { string BaseDirectory { get; set; } - void Execute(string code, IEnumerable references, IScriptPackSession scriptPackSession, object hostObject = null); + void Execute(string code, IEnumerable references, ScriptPackSession scriptPackSession); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptHostFactory.cs b/src/ScriptCs.Core/IScriptHostFactory.cs deleted file mode 100644 index 63c0787c..00000000 --- a/src/ScriptCs.Core/IScriptHostFactory.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ScriptCs.Contracts; - -namespace ScriptCs -{ - [InheritedExport] - public interface IScriptHostFactory - { - ScriptHost CreateScriptHost(IEnumerable contexts); - } -} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index d48e2817..cb3c55ff 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -39,7 +39,6 @@ - @@ -51,8 +50,6 @@ - - diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 7defa748..4871403e 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -12,20 +12,15 @@ public class ScriptExecutor : IScriptExecutor private readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; private readonly IScriptEngine _scriptEngine; - private readonly IScriptHostFactory _scriptHostFactory; [ImportingConstructor] - public ScriptExecutor(IFileSystem fileSystem, [Import(Constants.RunContractName)]IFilePreProcessor filePreProcessor, [Import(Constants.RunContractName)]IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory) + public ScriptExecutor(IFileSystem fileSystem, [Import(Constants.RunContractName)]IFilePreProcessor filePreProcessor, [Import(Constants.RunContractName)]IScriptEngine scriptEngine) { _fileSystem = fileSystem; _filePreProcessor = filePreProcessor; _scriptEngine = scriptEngine; - _scriptHostFactory = scriptHostFactory; } - public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) : - this(fileSystem, filePreProcessor, scriptEngine, new ScriptHostFactory()) { } - public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) { var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); @@ -38,9 +33,6 @@ public void Execute(string script, IEnumerable paths, IEnumerable x.GetContext()); - var host = _scriptHostFactory.CreateScriptHost(contexts); - using (var scriptPackSession = new ScriptPackSession(scriptPacks)) { var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); var code = _filePreProcessor.ProcessFile(path); @@ -48,8 +40,7 @@ public void Execute(string script, IEnumerable paths, IEnumerable _scriptPacks; + private IList _references; + private IList _namespaces; + public ScriptPackSession(IEnumerable scriptPacks) { _scriptPacks = scriptPacks; - References = new List(); - Namespaces = new List(); + _references = new List(); + _namespaces = new List(); InitializePacks(); } - public List References { get; private set; } - public List Namespaces { get; private set; } - + public IEnumerable ScriptPacks { get { return _scriptPacks; } } + public IEnumerable References { get { return _references; } } + public IEnumerable Namespaces { get { return _namespaces; } } + public void Dispose() { TerminatePacks(); @@ -41,12 +45,12 @@ private void TerminatePacks() void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) { - References.Add(assemblyDisplayNameOrPath); + _references.Add(assemblyDisplayNameOrPath); } void IScriptPackSession.ImportNamespace(string @namespace) { - Namespaces.Add(@namespace); + _namespaces.Add(@namespace); } } } diff --git a/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs b/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs new file mode 100644 index 00000000..5107c362 --- /dev/null +++ b/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using ScriptCs.Contracts; + +namespace ScriptCs.Engine.Roslyn +{ + [InheritedExport] + public interface IScriptHostFactory + { + ScriptHost CreateScriptHost(IEnumerable contexts); + } +} diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index bc5d9fc5..a74e4893 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -16,6 +16,10 @@ public class RoslynScriptDebuggerEngine : RoslynScriptEngine private const string AttachMessageTemplate = "Attach to process {0} and press ENTER. Then use the 'go' command in the debugger."; + [ImportingConstructor] + public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory) + : base(scriptHostFactory) { } + protected override void Execute(string code, Session session) { var submission = session.CompileSubmission(code); diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 8ede66fd..1d07d127 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -12,10 +12,14 @@ namespace ScriptCs.Engine.Roslyn public class RoslynScriptEngine : IScriptEngine { private readonly ScriptEngine _scriptEngine; + private readonly IScriptHostFactory _scriptHostFactory; - public RoslynScriptEngine() + [ImportingConstructor] + public RoslynScriptEngine(IScriptHostFactory scriptHostFactory) { _scriptEngine = new ScriptEngine(); + + _scriptHostFactory = scriptHostFactory; } public string BaseDirectory @@ -24,9 +28,12 @@ public string BaseDirectory set { _scriptEngine.BaseDirectory = value; } } - public void Execute(string code, IEnumerable references, IScriptPackSession scriptPackSession, object hostObject = null) + public void Execute(string code, IEnumerable references, ScriptPackSession scriptPackSession) { - var session = _scriptEngine.CreateSession(hostObject); + var contexts = scriptPackSession.ScriptPacks.Select(x => x.GetContext()); + var host = _scriptHostFactory.CreateScriptHost(contexts); + + var session = _scriptEngine.CreateSession(host); foreach (var reference in references) session.AddReference(reference); diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 2cfe65ad..7c33e3a2 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -48,9 +48,12 @@ + + + diff --git a/src/ScriptCs.Core/ScriptHost.cs b/src/ScriptCs.Engine.Roslyn/ScriptHost.cs similarity index 81% rename from src/ScriptCs.Core/ScriptHost.cs rename to src/ScriptCs.Engine.Roslyn/ScriptHost.cs index 2c6efcba..9130aac7 100644 --- a/src/ScriptCs.Core/ScriptHost.cs +++ b/src/ScriptCs.Engine.Roslyn/ScriptHost.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; +using System.ComponentModel.Composition; using System.Linq; using System.Text; using System.Threading.Tasks; +using ScriptCs; using ScriptCs.Contracts; -namespace ScriptCs +namespace ScriptCs.Engine.Roslyn { public class ScriptHost { diff --git a/src/ScriptCs.Core/ScriptHostFactory.cs b/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs similarity index 81% rename from src/ScriptCs.Core/ScriptHostFactory.cs rename to src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs index 684f2d7e..353d87f3 100644 --- a/src/ScriptCs.Core/ScriptHostFactory.cs +++ b/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using ScriptCs.Contracts; +using ScriptCs.Engine.Roslyn; - -namespace ScriptCs +namespace ScriptCs.Engine.Roslyn { public class ScriptHostFactory : IScriptHostFactory { diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index f508f17b..b05ffdcf 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -15,8 +15,7 @@ public class ScriptExecutorTests public static ScriptExecutor CreateScriptExecutor( Mock fileSystem = null, Mock fileProcessor = null, - Mock scriptEngine = null, - Mock scriptHostFactory = null) + Mock scriptEngine = null) { if (fileSystem == null) { @@ -32,14 +31,7 @@ public static ScriptExecutor CreateScriptExecutor( scriptEngine.SetupProperty(e => e.BaseDirectory); } - if (scriptHostFactory == null) - { - return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); - } - else - { - return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, scriptHostFactory.Object); - } + return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); } public class TheExecuteMethod @@ -156,7 +148,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut var recipes = Enumerable.Empty(); preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(code).Verifiable(); - scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny())); // act scriptExecutor.Execute(scriptName, paths, recipes); @@ -164,7 +156,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut // assert preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); - scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny(), It.IsAny()), Times.Once()); + scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny()), Times.Once()); } @@ -262,13 +254,13 @@ public void ShouldAddReferenceToEachDestinationFile() var destPaths = new string[] { "System", "System.Core", destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; - scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny())); // act scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); // assert - scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny(), It.IsAny()), Times.Once()); + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny()), Times.Once()); } [Fact] @@ -292,30 +284,6 @@ public void ShouldInitializeScriptPacks() scriptPack1.Verify(p => p.Initialize(It.IsAny())); } - [Fact] - public void ShouldCreateScriptHostWithContexts() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - - var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny>())).Returns((IEnumerable c) => new ScriptHost(c)); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptHostFactory: scriptHostFactory); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.Initialize(It.IsAny())); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); - - scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); - } - [Fact] public void ShouldTerminateScriptPacksWhenScriptFinishes() { diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index ab4c9a8a..6482bfac 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -15,12 +15,35 @@ private static RoslynScriptEngine CreateScriptEngine( { scriptHostFactory = scriptHostFactory ?? new Mock(); - return new RoslynScriptEngine(); + return new RoslynScriptEngine(scriptHostFactory.Object); } public class TheExecuteMethod { + [Fact] + public void ShouldCreateScriptHostWithContexts() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny>())).Returns((IEnumerable c) => new ScriptHost(c)); + + var code = "var a = 0;"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + + var scriptPackSession = new ScriptPackSession(new[] { scriptPack1.Object }); + + engine.Execute(code, Enumerable.Empty(), scriptPackSession); + + scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); + } } } } \ No newline at end of file From 0327312e7e55de0262688f26b7848059ae6664ff Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 12 Mar 2013 21:02:25 +0100 Subject: [PATCH 0081/1224] Added WPF sample. #84 --- samples/wpf/CalculatorView.xaml | 47 ++++++++++++ samples/wpf/app.csx | 26 +++++++ samples/wpf/mvvm.csx | 49 +++++++++++++ samples/wpf/utilities.csx | 15 ++++ samples/wpf/viewmodels.csx | 124 ++++++++++++++++++++++++++++++++ samples/wpf/views.csx | 7 ++ 6 files changed, 268 insertions(+) create mode 100644 samples/wpf/CalculatorView.xaml create mode 100644 samples/wpf/app.csx create mode 100644 samples/wpf/mvvm.csx create mode 100644 samples/wpf/utilities.csx create mode 100644 samples/wpf/viewmodels.csx create mode 100644 samples/wpf/views.csx diff --git a/samples/wpf/CalculatorView.xaml b/samples/wpf/CalculatorView.xaml new file mode 100644 index 00000000..57d7d172 --- /dev/null +++ b/samples/wpf/CalculatorView.xaml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/wpf/app.csx b/samples/wpf/app.csx new file mode 100644 index 00000000..57d59f0f --- /dev/null +++ b/samples/wpf/app.csx @@ -0,0 +1,26 @@ +#load utilities.csx +#load mvvm.csx + +#load viewmodels.csx +#load views.csx + +using System; +using System.Windows; + +public class App : Application +{ + protected override void OnStartup(StartupEventArgs e) + { + var viewModel = new CalculatorViewModel(); + + var window = new CalculatorView + { + DataContext = viewModel, + SizeToContent = SizeToContent.WidthAndHeight + }; + + window.Show(); + } +} + +new App().Run(); diff --git a/samples/wpf/mvvm.csx b/samples/wpf/mvvm.csx new file mode 100644 index 00000000..1f732677 --- /dev/null +++ b/samples/wpf/mvvm.csx @@ -0,0 +1,49 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Windows.Input; + +public class ViewModelBase : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void NotifyPropertyChanged(string propertyName) + { + var handler = PropertyChanged; + if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); + } +} + +public class RelayCommand : ICommand +{ + private readonly Action _execute; + + private readonly Func _canExecute; + + public RelayCommand(Action execute) : this(execute, null) { } + + public RelayCommand(Action execute, Func canExecute) + { + if (execute == null) throw new ArgumentNullException("execute"); + + _execute = execute; + _canExecute = canExecute; + } + + [DebuggerStepThrough] + public bool CanExecute(object parameter) + { + return _canExecute == null || _canExecute(parameter); + } + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public void Execute(object parameter) + { + _execute(parameter); + } +} \ No newline at end of file diff --git a/samples/wpf/utilities.csx b/samples/wpf/utilities.csx new file mode 100644 index 00000000..2e6f6607 --- /dev/null +++ b/samples/wpf/utilities.csx @@ -0,0 +1,15 @@ +using System.IO; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; + +public static class XamlUtility +{ + public static void LoadXaml(ContentControl contentControl, string xamlFile) + { + using (var fileStream = File.OpenRead(xamlFile)) + { + contentControl.Content = XamlReader.Load(fileStream) as DependencyObject; + } + } +} \ No newline at end of file diff --git a/samples/wpf/viewmodels.csx b/samples/wpf/viewmodels.csx new file mode 100644 index 00000000..790be2ba --- /dev/null +++ b/samples/wpf/viewmodels.csx @@ -0,0 +1,124 @@ +using System; +using System.Windows.Input; + +public class CalculatorViewModel : ViewModelBase +{ + private string _display; + + public CalculatorViewModel() + { + Display = "0"; + + NumberCommand = new RelayCommand(param => AddNumber(Convert.ToInt32(param)), param => CanAddNumber); + + AddCommand = CreateOperatorCommand('+'); + SubtractCommand = CreateOperatorCommand('-'); + MultiplyCommand = CreateOperatorCommand('*'); + DivideCommand = CreateOperatorCommand('/'); + + CalculateCommand = new RelayCommand(param => Calculate(), param => CanCalculate); + ClearCommand = new RelayCommand(param => Clear(), param => true); + } + + public string Display + { + get { return _display; } + set + { + _display = value; + NotifyPropertyChanged("Display"); + CommandManager.InvalidateRequerySuggested(); + } + } + + public RelayCommand NumberCommand { get; private set; } + + public RelayCommand AddCommand { get; private set; } + + public RelayCommand SubtractCommand { get; private set; } + + public RelayCommand MultiplyCommand { get; private set; } + + public RelayCommand DivideCommand { get; private set; } + + public RelayCommand CalculateCommand { get; private set; } + + public RelayCommand ClearCommand { get; private set; } + + private int? Operand1 { get; set; } + + private char? Operator { get; set; } + + private int? Operand2 { get; set; } + + private int? Result { get; set; } + + private bool CanApplyOperator + { + get { return Operand1.HasValue && !Operator.HasValue; } + } + + private void ApplyOperator(char @operator) + { + Operator = @operator; + Display = string.Format("{0} {1} ", Display, Operator); + } + + private bool CanAddNumber + { + get { return !Result.HasValue; } + } + + private void AddNumber(int number) + { + if (Operator.HasValue) + { + Operand2 = !Operand2.HasValue ? number : (Operand2 * 10) + number; + Display += number; + return; + } + + Operand1 = !Operand1.HasValue ? number : (Operand1 * 10) + number; + Display += number; + } + + private bool CanCalculate + { + get { return Operand1.HasValue && Operator.HasValue && Operand2.HasValue && !Result.HasValue; } + } + + private void Calculate() + { + switch (Operator) + { + case '+': + Result = Operand1 + Operand2; + break; + case '-': + Result = Operand1 - Operand2; + break; + case '*': + Result = Operand1 * Operand2; + break; + case '/': + Result = Operand1 / Operand2; + break; + } + + Display = Result.ToString(); + } + + private void Clear() + { + Operand1 = null; + Operator = null; + Operand2 = null; + Result = null; + Display = "0"; + } + + private RelayCommand CreateOperatorCommand(char @operator) + { + return new RelayCommand(param => ApplyOperator(@operator), param => CanApplyOperator); + } +} \ No newline at end of file diff --git a/samples/wpf/views.csx b/samples/wpf/views.csx new file mode 100644 index 00000000..79bdd685 --- /dev/null +++ b/samples/wpf/views.csx @@ -0,0 +1,7 @@ +public class CalculatorView : Window +{ + public CalculatorView() + { + XamlUtility.LoadXaml(this, "CalculatorView.xaml"); + } +} \ No newline at end of file From 9068353717cb816439c46b0f55a08b1f3b0ec8ba Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:01:11 -0400 Subject: [PATCH 0082/1224] Remove unnecessary MSBuild target 'GatherTestAssemblies' --- build/Build.proj | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/build/Build.proj b/build/Build.proj index 9b8a20bb..90600d66 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -11,6 +11,7 @@ $([System.IO.Path]::GetFullPath( '$(MSBuildThisFileDirectory)..\' )) $([System.IO.Path]::Combine( $(Root), 'artifacts\' )) $([System.IO.Path]::Combine( $(BaseArtifactsPath), $(Configuration) ))\ + $([System.IO.Path]::Combine( $(Root), 'common\CommonVersionInfo.cs' )) @@ -46,16 +47,16 @@ - - + + + + + + - - - - From e6c787aa0eb59174bf11a4fa9f0eeb3c9e66c185 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:03:19 -0400 Subject: [PATCH 0083/1224] The UpdateProjectVersions target should reset the CommonVersionInfo file after build --- build/Build.proj | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/build/Build.proj b/build/Build.proj index 90600d66..80eebf2c 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -21,17 +21,8 @@ ArtifactsPath=$(ArtifactsPath) - - - - AssemblyVersion\("\d+\.\d+\.\d+"\) - AssemblyVersion("$(AssemblyVersion)") - - - AssemblyInformationalVersion\("\d+\.\d+\.\d+(-\w+\d*(-\d+)?)?"\) - AssemblyInformationalVersion("$(PackageVersion)") - + @@ -58,9 +49,16 @@ + + + + + + - - + + + \ No newline at end of file From 8463429febfd06b60d1506bfcd06a7ba5a14d0fe Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:04:29 -0400 Subject: [PATCH 0084/1224] The solution should be cleaned before the output directory is removed --- build/Build.proj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Build.proj b/build/Build.proj index 80eebf2c..c13a9d05 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -28,8 +28,8 @@ - + From c16062dc58b300f2db8a3c746cc3caf26e0dd64e Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:05:16 -0400 Subject: [PATCH 0085/1224] Use the same output folder for all projects --- build/ScriptCs.Common.props | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/build/ScriptCs.Common.props b/build/ScriptCs.Common.props index fa04ec5a..e54388b8 100644 --- a/build/ScriptCs.Common.props +++ b/build/ScriptCs.Common.props @@ -25,11 +25,10 @@ - $(MSBuildProjectName)\bin\ - $(MSBuildProjectName)\obj\ + - $([System.IO.Path]::Combine($(ArtifactsPath), $(ProjectOutputPath))) - $([System.IO.Path]::Combine($(ArtifactsPath), $(ProjectIntermediatePath))) + $([System.IO.Path]::Combine($(ArtifactsPath), 'bin\')) + From f1381538f2e7427e296bff0bb9d3dd908808417e Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:11:11 -0400 Subject: [PATCH 0086/1224] Create AssemblyAttributes item group for the UpdateProjectVersions target --- build/ScriptCs.Version.props | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 99075bdb..15bea9e1 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -18,4 +18,13 @@ $(MajorVersion).$(MinorVersion).$(PatchVersion) $(PackageVersion)-$(BuildQuality) + + + + <_Parameter1>$(AssemblyVersion) + + + <_Parameter1>$(PackageVersion) + + \ No newline at end of file From e1f93a69aa96b8d8604fdbd15b72c081c06fc593 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:11:46 -0400 Subject: [PATCH 0087/1224] Update project *.nuspec files with the correct information --- .../Properties/ScriptCs.Contracts.nuspec | 18 +++++++++++------- .../Properties/ScriptCs.Core.nuspec | 18 +++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec b/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec index b95ab90a..85046f92 100644 --- a/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec +++ b/src/ScriptCs.Contracts/Properties/ScriptCs.Contracts.nuspec @@ -1,13 +1,17 @@ - + - $id$ - $version$ - $author$ + ScriptCs.Contracts + 0.0.0 + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + Glenn Block, Justin Rusbatch, Filip Wojcieszyn https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md http://scriptcs.net - $description$ + http://www.gravatar.com/avatar/5c754f646971d8bc800b9d4057931938.png?s=120 + ScriptCs.Contracts contains the components necessary to create script packs for scriptcs. + roslyn csx script packs + + + - - \ No newline at end of file diff --git a/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec b/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec index b95ab90a..50f75041 100644 --- a/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec +++ b/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec @@ -1,13 +1,17 @@ - + - $id$ - $version$ - $author$ + ScriptCs.Core + 0.0.0 + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + Glenn Block, Justin Rusbatch, Filip Wojcieszyn https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md http://scriptcs.net - $description$ + http://www.gravatar.com/avatar/5c754f646971d8bc800b9d4057931938.png?s=120 + ScriptCs.Core is the core framework assembly for scriptcs. + roslyn csx + + + - - \ No newline at end of file From 2c9ea53253d07251d9f5bc6364a70419a097cbde Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:12:50 -0400 Subject: [PATCH 0088/1224] Create NuGet packages for Core and Contracts on build #46 --- build/Build.proj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build/Build.proj b/build/Build.proj index c13a9d05..c3378cdd 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -11,6 +11,9 @@ $([System.IO.Path]::GetFullPath( '$(MSBuildThisFileDirectory)..\' )) $([System.IO.Path]::Combine( $(Root), 'artifacts\' )) $([System.IO.Path]::Combine( $(BaseArtifactsPath), $(Configuration) ))\ + $(ArtifactsPath.TrimEnd(new[] { '\' })) + $([System.IO.Path]::Combine( $(Root), '.nuget\nuget.exe' )) + $([System.IO.Path]::Combine( $(Root), 'common\CommonVersionInfo.cs' )) @@ -48,7 +51,12 @@ + + + + + From 6fe2e739c3b3fb7cd123f7f576421d97e23310c2 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:30:34 -0400 Subject: [PATCH 0089/1224] ScriptCs.Core.nuspec should depend on the ScriptCs.Contracts package --- src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec b/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec index 50f75041..d9662648 100644 --- a/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec +++ b/src/ScriptCs.Core/Properties/ScriptCs.Core.nuspec @@ -13,5 +13,8 @@ + + + \ No newline at end of file From a1a98f0c8b626b3ba0f231f3133c7a30b88ad4ba Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 12 Mar 2013 18:31:07 -0400 Subject: [PATCH 0090/1224] NuGet should pack by project file rather than through the nuspec file directly --- build/Build.proj | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/build/Build.proj b/build/Build.proj index c3378cdd..9f75a8f0 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -50,11 +50,8 @@ - - - - - + + From 249e6ba3411ac88df8a5cca0c627c3b704d29793 Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Tue, 12 Mar 2013 21:35:23 -0300 Subject: [PATCH 0091/1224] Update ScriptCs.Engine.Roslyn.csproj --- .../ScriptCs.Engine.Roslyn.csproj | 33 ++----------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 7c33e3a2..38da31c7 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -1,36 +1,14 @@  - + - Debug - AnyCPU {E79EC231-E27D-4057-91C9-2D001A3A8C3B} Library Properties ScriptCs.Engine.Roslyn ScriptCs.Engine.Roslyn - v4.5 - 512 - ..\..\ true - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll @@ -70,11 +48,4 @@ - - \ No newline at end of file + From 76245ddf435de22ffaafb9855ee4edb442e32495 Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Tue, 12 Mar 2013 21:39:06 -0300 Subject: [PATCH 0092/1224] Update ScriptCs.Engine.Roslyn.Tests.csproj --- .../ScriptCs.Engine.Roslyn.Tests.csproj | 35 ++----------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj index 0434bb7c..d6f89a0c 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj @@ -1,35 +1,11 @@  - + - Debug - AnyCPU {28D11DE5-9F98-4E0A-8CCC-9CDC19110451} Library - Properties ScriptCs.Tests ScriptCs.Engine.Roslyn.Tests - v4.5 - 512 - ..\..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 @@ -78,11 +54,4 @@ - - \ No newline at end of file + From 4ac03920e3a44d0f32a6c17aa302e2c46dfb3807 Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Tue, 12 Mar 2013 21:35:23 -0300 Subject: [PATCH 0093/1224] Update ScriptCs.Engine.Roslyn.csproj --- .../ScriptCs.Engine.Roslyn.csproj | 35 ++----------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 7c33e3a2..3ad8cc1b 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -1,35 +1,11 @@  - + - Debug - AnyCPU {E79EC231-E27D-4057-91C9-2D001A3A8C3B} Library - Properties ScriptCs.Engine.Roslyn ScriptCs.Engine.Roslyn - v4.5 - 512 - ..\..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 @@ -70,11 +46,4 @@ - - \ No newline at end of file + From fea1be63f841a9d62f801ae702e37cdc554d600a Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Tue, 12 Mar 2013 22:26:20 -0400 Subject: [PATCH 0094/1224] removed IDisposable from ScriptPackSession --- src/ScriptCs.Core/ScriptExecutor.cs | 19 +++--- src/ScriptCs.Core/ScriptPackSession.cs | 89 ++++++++++++-------------- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 4871403e..c30bab06 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -33,15 +33,18 @@ public void Execute(string script, IEnumerable paths, IEnumerable PrepareBinFolder(IEnumerable paths, string bin) diff --git a/src/ScriptCs.Core/ScriptPackSession.cs b/src/ScriptCs.Core/ScriptPackSession.cs index e3312360..8f56e471 100644 --- a/src/ScriptCs.Core/ScriptPackSession.cs +++ b/src/ScriptCs.Core/ScriptPackSession.cs @@ -5,52 +5,45 @@ namespace ScriptCs { - public class ScriptPackSession : IScriptPackSession, IDisposable - { - private readonly IEnumerable _scriptPacks; - - private IList _references; - private IList _namespaces; - - public ScriptPackSession(IEnumerable scriptPacks) - { - _scriptPacks = scriptPacks; - - _references = new List(); - _namespaces = new List(); - - InitializePacks(); - } - - public IEnumerable ScriptPacks { get { return _scriptPacks; } } - public IEnumerable References { get { return _references; } } - public IEnumerable Namespaces { get { return _namespaces; } } - - public void Dispose() - { - TerminatePacks(); - } - - private void InitializePacks() - { - foreach (var s in _scriptPacks) - s.Initialize(this); - } - - private void TerminatePacks() - { - foreach (var s in _scriptPacks) - s.Terminate(); - } - - void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) - { - _references.Add(assemblyDisplayNameOrPath); - } - - void IScriptPackSession.ImportNamespace(string @namespace) - { - _namespaces.Add(@namespace); - } - } + public class ScriptPackSession : IScriptPackSession + { + private readonly IEnumerable _scriptPacks; + + private IList _references; + private IList _namespaces; + + public ScriptPackSession(IEnumerable scriptPacks) + { + _scriptPacks = scriptPacks; + + _references = new List(); + _namespaces = new List(); + } + + public IEnumerable ScriptPacks { get { return _scriptPacks; } } + public IEnumerable References { get { return _references; } } + public IEnumerable Namespaces { get { return _namespaces; } } + + public void InitializePacks() + { + foreach (var s in _scriptPacks) + s.Initialize(this); + } + + public void TerminatePacks() + { + foreach (var s in _scriptPacks) + s.Terminate(); + } + + void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) + { + _references.Add(assemblyDisplayNameOrPath); + } + + void IScriptPackSession.ImportNamespace(string @namespace) + { + _namespaces.Add(@namespace); + } + } } From e46d53e6a34d0ae5aadc5876ae63d9d8af3e278e Mon Sep 17 00:00:00 2001 From: Filip W Date: Tue, 12 Mar 2013 23:58:51 -0400 Subject: [PATCH 0095/1224] fixed bug with #r not loading, and set #load to only be available at the top #105 #98 #21 --- src/ScriptCs.Core/DebugFilePreProcessor.cs | 2 +- src/ScriptCs.Core/FilePreProcessor.cs | 81 ++++- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 342 ++++++++++++------ 3 files changed, 291 insertions(+), 134 deletions(-) diff --git a/src/ScriptCs.Core/DebugFilePreProcessor.cs b/src/ScriptCs.Core/DebugFilePreProcessor.cs index cafe47cd..2277933b 100644 --- a/src/ScriptCs.Core/DebugFilePreProcessor.cs +++ b/src/ScriptCs.Core/DebugFilePreProcessor.cs @@ -22,7 +22,7 @@ protected override string GenerateUsings(ICollection usingLines) usingLines.Add(SystemDiagnosticsUsing); } - return string.Join(_fileSystem.NewLine, usingLines); + return string.Join(_fileSystem.NewLine, usingLines.Distinct()); } } } diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 4d99ee98..d97fdd8a 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -10,6 +10,7 @@ public class FilePreProcessor : IFilePreProcessor { private const string LoadString = "#load "; private const string UsingString = "using "; + private const string RString = "#r "; protected readonly IFileSystem _fileSystem; @@ -22,25 +23,44 @@ public FilePreProcessor(IFileSystem fileSystem) public string ProcessFile(string path) { var entryFile = _fileSystem.ReadFileLines(path); - var parsed = ParseFile(entryFile); + var usings = new List(); + var rs = new List(); + var loads = new List(); + + var parsed = ParseFile(entryFile, ref usings, ref rs, ref loads); + + var result = GenerateRs(rs); + if (!string.IsNullOrWhiteSpace(result)) + { + result += _fileSystem.NewLine; + } + + result += GenerateUsings(usings); + if (!string.IsNullOrWhiteSpace(result)) + { + result += _fileSystem.NewLine; + } - // item1 === usings; item2 === code - var result = GenerateUsings(parsed.Item1); - result += _fileSystem.NewLine + parsed.Item2; + result += parsed; return result; } protected virtual string GenerateUsings(ICollection usingLines) { - return string.Join(_fileSystem.NewLine, usingLines); + return string.Join(_fileSystem.NewLine, usingLines.Distinct()); } - private Tuple, string> ParseFile(IEnumerable file) + protected virtual string GenerateRs(ICollection rLines) { - var usings = new List(); + return string.Join(_fileSystem.NewLine, rLines.Distinct()); + } + private string ParseFile(IEnumerable file, ref List usings, ref List rs, ref List loads) + { var fileList = file.ToList(); + var firstCode = fileList.FindIndex(i => IsNonDirectiveLine(i)); + for (var i = 0; i < fileList.Count; i++) { var line = fileList[i]; @@ -49,33 +69,60 @@ private Tuple, string> ParseFile(IEnumerable file) usings.Add(line); } + if (IsRLine(line)) + { + if (i < firstCode) + { + rs.Add(line); + } + else + { + fileList[i] = string.Empty; + } + } + if (IsLoadLine(line)) { - var filepath = line.Trim(' ').Replace(LoadString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); - var filecontent = _fileSystem.IsPathRooted(filepath) + if (i < firstCode && !loads.Contains(line)) + { + var filepath = line.Trim(' ').Replace(LoadString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); + var filecontent = _fileSystem.IsPathRooted(filepath) ? _fileSystem.ReadFileLines(filepath) : _fileSystem.ReadFileLines(_fileSystem.CurrentDirectory + @"\" + filepath); - if (filecontent != null) + if (filecontent != null) + { + loads.Add(line); + var parsed = ParseFile(filecontent, ref usings, ref rs, ref loads); + fileList[i] = "//" + filepath + _fileSystem.NewLine + parsed; + } + } + else { - var parsed = ParseFile(filecontent); - fileList[i] = parsed.Item2; - usings.AddRange(parsed.Item1); + fileList[i] = string.Empty; } } } - var result = string.Join(_fileSystem.NewLine, fileList.Where(line => !IsUsingLine(line))); - var tuple = new Tuple, string>(usings.Distinct().ToList(), result); + var result = string.Join(_fileSystem.NewLine, fileList.Where(line => !IsUsingLine(line) && !IsRLine(line))); + return result; + } - return tuple; - } + private static bool IsNonDirectiveLine(string line) + { + return !IsRLine(line) && !IsLoadLine(line) && line.Trim() != string.Empty; + } private static bool IsUsingLine(string line) { return line.TrimStart(' ').StartsWith(UsingString) && !line.Contains("{") && line.Contains(";"); } + private static bool IsRLine(string line) + { + return line.TrimStart(' ').StartsWith(RString); + } + private static bool IsLoadLine(string line) { return line.TrimStart(' ').StartsWith(LoadString); diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index 122681b1..bc94a215 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -3,151 +3,261 @@ using System.Linq; using System.Text; using Moq; +using Should; using Xunit; namespace ScriptCs.Tests { public class FileProcessorTests { - private List file1 = new List + public class ProcessFileMethod + { + private List _file1 = new List + { + @"#load ""script2.csx""", + @"#load ""script4.csx"";", + "using System;", + @"Console.WriteLine(""Hello Script 1"");", + @"Console.WriteLine(""Loading Script 2"");", + @"Console.WriteLine(""Loaded Script 2"");", + @"Console.WriteLine(""Loading Script 4"");", + @"Console.WriteLine(""Loaded Script 4"");", + @"Console.WriteLine(""Goodbye Script 1"");" + }; + + private List _file2 = new List + { + "using System;", + @"Console.WriteLine(""Hello Script 2"");", + @"Console.WriteLine(""Loading Script 3"");", + @"#load ""script3.csx""", + @"Console.WriteLine(""Loaded Script 3"");", + @"Console.WriteLine(""Goodbye Script 2"");" + }; + + private readonly List _file3 = new List + { + "using System;", + "using System.Collections.Generic;", + @"Console.WriteLine(""Hello Script 3"");", + @"Console.WriteLine(""Goodbye Script 3"");" + }; + + private readonly List _file4 = new List + { + "using System;", + "using System.Core;", + @"Console.WriteLine(""Hello Script 4"");", + @"Console.WriteLine(""Goodbye Script 4"");" + }; + + private readonly Mock _fileSystem; + + public ProcessFileMethod() { - "using System;", - @"Console.WriteLine(""Hello Script 1"");", - @"Console.WriteLine(""Loading Script 2"");", - @"#load ""script2.csx""", - @"Console.WriteLine(""Loaded Script 2"");", - @"Console.WriteLine(""Loading Script 4"");", - @"#load ""script4.csx"";", - @"Console.WriteLine(""Loaded Script 4"");", - @"Console.WriteLine(""Goodbye Script 1"");" - }; - - private List file2 = new List + _fileSystem = new Mock(); + _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + .Returns(_file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + .Returns(_file2.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) + .Returns(_file3.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + .Returns(_file4.ToArray()); + } + + [Fact] + public void MultipleUsingStatementsShouldProduceDistinctOutput() { - "using System;", - @"Console.WriteLine(""Hello Script 2"");", - @"Console.WriteLine(""Loading Script 3"");", - @"#load ""script3.csx""", - @"Console.WriteLine(""Loaded Script 3"");", - @"Console.WriteLine(""Goodbye Script 2"");" - }; - - private List file3 = new List + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))), Times.Exactly(3)); + Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + } + + [Fact] + public void UsingStateMentsShoulAllBeAtTheTop() { - "using System;", - "using System.Collections.Generic;", - @"Console.WriteLine(""Hello Script 3"");", - @"Console.WriteLine(""Goodbye Script 3"");" - }; + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); - private List file4 = new List + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + + Assert.True(lastUsing < firsNotUsing); + } + + [Fact] + public void ShouldNotLoadInlineLoads() { - "using System;", - "using System.Core;", - @"Console.WriteLine(""Hello Script 4"");", - @"Console.WriteLine(""Goodbye Script 4"");" - }; + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); - private readonly Mock _fileSystem; + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + } - public FileProcessorTests() - { - _fileSystem = new Mock(); - _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) - .Returns(file1.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) - .Returns(file2.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) - .Returns(file3.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) - .Returns(file4.ToArray()); - } + [Fact] + public void ShouldNotLoadSameFileTwice() + { + var file = new List + { + @"#load ""script4.csx""", + "using System;", + @"Console.WriteLine(""Hello Script 2"");", + }; - [Fact] - public void MultipleUsingStatementsShouldProduceDistinctOutput() - { - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\script1.csx"); + var fs = new Mock(); + fs.Setup(i => i.NewLine).Returns(Environment.NewLine); + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + .Returns(file.ToArray()); + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + .Returns(_file4.ToArray()); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))),Times.Exactly(4)); - Assert.Equal(3, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); - } + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + } - [Fact] - public void UsingStateMentsShoulAllBeAtTheTop() - { - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\script1.csx"); + [Fact] + public void LoadBeforeUsingShouldBeAllowed() + { + var file = new List + { + @"#load ""script4.csx""", + "", + "using System;", + @"Console.WriteLine(""abc"");" + }; - var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); - var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); - Assert.True(lastUsing < firsNotUsing); - } + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); - [Fact] - public void ThreeLoadedFilesShoulAllBeCalledOnce() - { - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\script1.csx"); + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); - } + splitOutput.Count(x => x.TrimStart(' ').StartsWith("using ")).ShouldEqual(2); + Assert.True(lastUsing < firsNotUsing); + } - [Fact] - public void LoadBeforeUsingShouldBeAllowed() - { - var file = new List - { - @"#load ""script4.csx""", - "", - "using System;", - @"Console.WriteLine(""abc"");" - }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + [Fact] + public void ShouldNotBeAllowedToLoadAfterUsing() + { + var file = new List + { + "using System;", + @"Console.WriteLine(""abc"");", + @"#load ""script4.csx""" + }; + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\file.csx"); + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); - var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); - var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); - Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); - Assert.True(lastUsing < firsNotUsing); - } + Assert.Equal(1, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + Assert.Equal(3, splitOutput.Length); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); + } - [Fact] - public void UsingInCodeDoesNotCountAsUsingImport() - { - var file = new List - { - @"#load ""script4.csx""", - "", - "using System;", - "using System.IO;", - "Console.WriteLine();", - @"using (var stream = new MemoryStream) {", - @"//do stuff", - @"}" - }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + [Fact] + public void UsingInCodeDoesNotCountAsUsingImport() + { + var file = new List + { + @"#load ""script4.csx""", + "", + "using System;", + "using System.IO;", + "Console.WriteLine();", + @"using (var stream = new MemoryStream) {", + @"//do stuff", + @"}" + }; + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); + + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var firstNonImportUsing = + splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); + var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); + + Assert.True(firstNonImportUsing > firstCodeLine); + } + + [Fact] + public void ShouldHaveReferencesOnTop() + { + var file1 = new List + { + @"#r ""My.dll""", + @"#load ""script2.csx""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + var fs = new Mock(); + fs.Setup(i => i.NewLine).Returns(Environment.NewLine); + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))).Returns(file1.ToArray()); + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))).Returns(_file2.ToArray()); + + var processor = new FilePreProcessor(fs.Object); + var output = processor.ProcessFile("\\script1.csx"); + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None).ToList(); + + var lastR = splitOutput.FindLastIndex(line => line.StartsWith("#r ")); + var firstNotR = splitOutput.FindIndex(line => !line.StartsWith("#r ")); + + lastR.ShouldNotEqual(-1); + Assert.True(lastR < firstNotR); + } + + [Fact] + public void ShouldHaveReferencesFromAllFiles() + { + var file1 = new List + { + @"#r ""My.dll""", + @"#load ""scriptX.csx""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + var file2 = new List + { + @"#r ""My2.dll""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\file.csx"); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + .Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\scriptX.csx"))) + .Returns(file2.ToArray()); - var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var firstNonImportUsing = splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); - var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); - Assert.True(firstNonImportUsing > firstCodeLine); + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + splitOutput.Count(line => line.StartsWith("#r ")).ShouldEqual(2); + } } } } From 35fdbf54edc354bb877565fb17f4c2d78d0da7b5 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Wed, 13 Mar 2013 01:39:43 -0300 Subject: [PATCH 0096/1224] # Updated FilePreProcessor.cs, FileProcessorTests.cs and RoslynScriptDebuggerEngine.cs to add #line directives after #loads --- src/ScriptCs.Core/FilePreProcessor.cs | 58 +++-- .../RoslynScriptDebuggerEngine.cs | 20 +- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 232 ++++++++++++------ 3 files changed, 212 insertions(+), 98 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 542c03e0..51623e4b 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -18,8 +18,8 @@ public FilePreProcessor(IFileSystem fileSystem) public string ProcessFile(string path) { - var entryFile = _fileSystem.ReadFileLines(path); - var parsed = ParseFile(entryFile); + var lines = _fileSystem.ReadFileLines(path); + var parsed = ParseFile(path, lines); // item1 === usings; item2 === code var result = GenerateUsings(parsed.Item1); @@ -33,36 +33,56 @@ protected virtual string GenerateUsings(ICollection usingLines) return string.Join(_fileSystem.NewLine, usingLines); } - private Tuple, string> ParseFile(IEnumerable file) + private Tuple, string> ParseFile(string path, IEnumerable lines) { var usings = new List(); + var linesList = lines.ToList(); - var fileList = file.ToList(); - for (var i = 0; i < fileList.Count; i++) + var parsingStatus = ParsingStatus.NoRestrictions; + + for (var i = 0; i < linesList.Count; i++) { - var line = fileList[i]; + var line = linesList[i]; if (IsUsingLine(line)) { usings.Add(line); } - - if (IsLoadLine(line)) + else if (IsLoadLine(line)) { - var filepath = line.Trim(' ').Replace(LoadString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); + if (parsingStatus == ParsingStatus.NoRestrictions) + { + parsingStatus = ParsingStatus.ForbidUsings; + } + + var filepath = + line.Trim(' ') + .Replace(LoadString, string.Empty) + .Replace("\"", string.Empty) + .Replace(";", string.Empty); var filecontent = _fileSystem.IsPathRooted(filepath) - ? _fileSystem.ReadFileLines(filepath) - : _fileSystem.ReadFileLines(_fileSystem.CurrentDirectory + @"\" + filepath); + ? _fileSystem.ReadFileLines(filepath) + : _fileSystem.ReadFileLines(_fileSystem.CurrentDirectory + @"\" + filepath); if (filecontent != null) { - var parsed = ParseFile(filecontent); - fileList[i] = parsed.Item2; + var parsed = ParseFile(filepath, filecontent); + linesList[i] = parsed.Item2; usings.AddRange(parsed.Item1); } } + else if (parsingStatus != ParsingStatus.ForbidLoads) + { + // we are in the first body line (until we add support for #r) + // add #line statement + parsingStatus = ParsingStatus.ForbidLoads; + + // +1 because we are in a zero indexed list, but line numbers are 1 indexed + // we need to keep the original position of the actual line + linesList.Insert(i, string.Format(@"#line {0} ""{1}""", i + 1, path)); + } } - var result = string.Join(_fileSystem.NewLine, fileList.Where(line => !IsUsingLine(line))); + var result = string.Join(_fileSystem.NewLine, linesList.Where(line => !IsUsingLine(line))); var tuple = new Tuple, string>(usings.Distinct().ToList(), result); return tuple; @@ -77,5 +97,15 @@ private static bool IsLoadLine(string line) { return line.TrimStart(' ').StartsWith(LoadString); } + + [Flags] + private enum ParsingStatus + { + ForbidLoads, + + ForbidUsings, + + NoRestrictions + } } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index 85ce59bf..feac7755 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -11,8 +10,6 @@ public class RoslynScriptDebuggerEngine : RoslynScriptEngine { private const string CompiledScriptClass = "Submission#0"; private const string CompiledScriptMethod = ""; - private const string AttachMessageTemplate = - "Attach to process {0} and press ENTER. Then use the 'go' command in the debugger."; public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory) : base(scriptHostFactory) @@ -27,28 +24,29 @@ protected override void Execute(string code, Session session) var compileSuccess = false; using (var exeStream = new MemoryStream()) - using (var pdbStream = new MemoryStream()) { + using (var pdbStream = new MemoryStream()) + { var result = submission.Compilation.Emit(exeStream, pdbStream: pdbStream); compileSuccess = result.Success; - if (result.Success) { + if (result.Success) + { exeBytes = exeStream.ToArray(); pdbBytes = pdbStream.ToArray(); - } else { + } + else + { var errors = String.Join(Environment.NewLine, result.Diagnostics.Select(x => x.ToString())); Console.WriteLine(errors); } } - if (compileSuccess) { + if (compileSuccess) + { var assembly = AppDomain.CurrentDomain.Load(exeBytes, pdbBytes); var type = assembly.GetType(CompiledScriptClass); var method = type.GetMethod(CompiledScriptMethod, BindingFlags.Static | BindingFlags.Public); - var pid = Process.GetCurrentProcess().Id; - Console.WriteLine(AttachMessageTemplate, pid); - Console.ReadLine(); - method.Invoke(null, new[] { session }); } } diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index 122681b1..805e495d 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -1,15 +1,17 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using Moq; +using Should; using Xunit; namespace ScriptCs.Tests { public class FileProcessorTests { - private List file1 = new List + public class TheProcessFileMethod + { + private List file1 = new List { "using System;", @"Console.WriteLine(""Hello Script 1"");", @@ -22,7 +24,7 @@ public class FileProcessorTests @"Console.WriteLine(""Goodbye Script 1"");" }; - private List file2 = new List + private List file2 = new List { "using System;", @"Console.WriteLine(""Hello Script 2"");", @@ -32,7 +34,7 @@ public class FileProcessorTests @"Console.WriteLine(""Goodbye Script 2"");" }; - private List file3 = new List + private List file3 = new List { "using System;", "using System.Collections.Generic;", @@ -40,7 +42,7 @@ public class FileProcessorTests @"Console.WriteLine(""Goodbye Script 3"");" }; - private List file4 = new List + private List file4 = new List { "using System;", "using System.Core;", @@ -48,86 +50,86 @@ public class FileProcessorTests @"Console.WriteLine(""Goodbye Script 4"");" }; - private readonly Mock _fileSystem; - - public FileProcessorTests() - { - _fileSystem = new Mock(); - _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) - .Returns(file1.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) - .Returns(file2.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) - .Returns(file3.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) - .Returns(file4.ToArray()); - } + private readonly Mock _fileSystem; - [Fact] - public void MultipleUsingStatementsShouldProduceDistinctOutput() - { - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\script1.csx"); + public TheProcessFileMethod() + { + _fileSystem = new Mock(); + _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + .Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + .Returns(file2.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) + .Returns(file3.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + .Returns(file4.ToArray()); + } + + [Fact] + public void MultipleUsingStatementsShouldProduceDistinctOutput() + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))),Times.Exactly(4)); - Assert.Equal(3, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); - } + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))), Times.Exactly(4)); + Assert.Equal(3, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + } - [Fact] - public void UsingStateMentsShoulAllBeAtTheTop() - { - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\script1.csx"); + [Fact] + public void UsingStateMentsShoulAllBeAtTheTop() + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); - var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); - var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); - Assert.True(lastUsing < firsNotUsing); - } + Assert.True(lastUsing < firsNotUsing); + } - [Fact] - public void ThreeLoadedFilesShoulAllBeCalledOnce() - { - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\script1.csx"); + [Fact] + public void ThreeLoadedFilesShoulAllBeCalledOnce() + { + var processor = new FilePreProcessor(_fileSystem.Object); + processor.ProcessFile("\\script1.csx"); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); - } + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + } - [Fact] - public void LoadBeforeUsingShouldBeAllowed() - { - var file = new List + [Fact] + public void LoadBeforeUsingShouldBeAllowed() + { + var file = new List { @"#load ""script4.csx""", "", "using System;", @"Console.WriteLine(""abc"");" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\file.csx"); + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); - var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); - var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); - Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); - Assert.True(lastUsing < firsNotUsing); - } + Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + Assert.True(lastUsing < firsNotUsing); + } - [Fact] - public void UsingInCodeDoesNotCountAsUsingImport() - { - var file = new List + [Fact] + public void UsingInCodeDoesNotCountAsUsingImport() + { + var file = new List { @"#load ""script4.csx""", "", @@ -138,16 +140,100 @@ public void UsingInCodeDoesNotCountAsUsingImport() @"//do stuff", @"}" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); - var processor = new FilePreProcessor(_fileSystem.Object); - var output = processor.ProcessFile("\\file.csx"); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); - var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var firstNonImportUsing = splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); - var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var firstNonImportUsing = splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); + var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); - Assert.True(firstNonImportUsing > firstCodeLine); + Assert.True(firstNonImportUsing > firstCodeLine); + } + + [Fact] + public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() + { + // f1 has usings and then loads + var f1 = new List + { + "using System;", + "using System.Diagnostics;", + @"#load ""C:\f2.csx"";", + @"#load ""C:\f3.csx"";", + @"Console.WriteLine(""First line of f1"");", + }; + + // f2 has no usings and multiple loads + var f2 = new List + { + @"#load ""C:\f4.csx"";", + @"#load ""C:\f5.csx"";", + @"Console.WriteLine(""First line of f2"");", + }; + + // f3 has usings and no loads + var f3 = new List + { + @"using System;", + @"using System.Diagnostics;", + @"Console.WriteLine(""First line of f3"");", + }; + + // f4 has no usings and no loads + var f4 = new List + { + @"Console.WriteLine(""First line of f4"");", + }; + + // f5 is no special case, just used to be loaded + var f5 = new List + { + @"using System;", + @"Console.WriteLine(""First line of f5"");", + }; + + _fileSystem.SetupGet(fs => fs.NewLine).Returns(Environment.NewLine); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f1.csx")) + .Returns(f1.ToArray()); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f2.csx")) + .Returns(f2.ToArray()).Verifiable(); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f3.csx")) + .Returns(f3.ToArray()); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f4.csx")) + .Returns(f4.ToArray()); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f5.csx")) + .Returns(f5.ToArray()); + _fileSystem.Setup(fs => fs.IsPathRooted(It.IsAny())).Returns(true); + + var preProcessor = new FilePreProcessor(_fileSystem.Object); + + var file = preProcessor.ProcessFile(@"C:\f1.csx"); + + var fileLines = file.Split(new[]{ Environment.NewLine }, StringSplitOptions.None); + + // using statements go first, after that f4 -> f5 -> f2 -> f3 -> f1 + var line = 0; + fileLines[line++].ShouldEqual("using System;"); + fileLines[line++].ShouldEqual("using System.Diagnostics;"); + + fileLines[line++].ShouldEqual(@"#line 1 ""C:\f4.csx"""); + fileLines[line++].ShouldEqual(f4[0]); + + fileLines[line++].ShouldEqual(@"#line 2 ""C:\f5.csx"""); + fileLines[line++].ShouldEqual(f5[1]); + + fileLines[line++].ShouldEqual(@"#line 3 ""C:\f2.csx"""); + fileLines[line++].ShouldEqual(f2[2]); + + fileLines[line++].ShouldEqual(@"#line 3 ""C:\f3.csx"""); + fileLines[line++].ShouldEqual(f3[2]); + + fileLines[line++].ShouldEqual(@"#line 5 ""C:\f1.csx"""); + fileLines[line].ShouldEqual(f1[4]); + } } } } From 9ddb6d3e6a762669375d1c44530f7e5e0fa88dc9 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Wed, 13 Mar 2013 01:43:06 -0300 Subject: [PATCH 0097/1224] # Deleted DebugFilePreProcessor.cs. No longer needed with support for debugging in VS --- src/ScriptCs.Core/DebugFilePreProcessor.cs | 25 ---------------------- src/ScriptCs.Core/ScriptCs.Core.csproj | 1 - src/ScriptCs/Program.cs | 3 +-- 3 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 src/ScriptCs.Core/DebugFilePreProcessor.cs diff --git a/src/ScriptCs.Core/DebugFilePreProcessor.cs b/src/ScriptCs.Core/DebugFilePreProcessor.cs deleted file mode 100644 index 7a3ac7b3..00000000 --- a/src/ScriptCs.Core/DebugFilePreProcessor.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace ScriptCs -{ - public class DebugFilePreProcessor : FilePreProcessor - { - private const string SystemDiagnosticsUsing = "using System.Diagnostics;"; - - public DebugFilePreProcessor(IFileSystem fileSystem) - : base(fileSystem) - { - } - - protected override string GenerateUsings(ICollection usingLines) - { - if (usingLines.Count(l => l.Equals(SystemDiagnosticsUsing)) == 0) - { - usingLines.Add(SystemDiagnosticsUsing); - } - - return string.Join(_fileSystem.NewLine, usingLines); - } - } -} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index cb3c55ff..109637c4 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -23,7 +23,6 @@ - diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index cedb9a4b..6bee9869 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -88,17 +88,16 @@ private static RegistrationBuilder SetupMefConventions(bool debug) conventions.ForTypesDerivedFrom().Export(); conventions.ForTypesDerivedFrom().Export(); conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); if (debug) { conventions.ForType().Export(); - conventions.ForType().Export(); conventions.ForType().Export(); } else { conventions.ForType().Export(); - conventions.ForType().Export(); conventions.ForType().Export(); } From 362ff4e80bb5f5dec8972402cd77aea683227d67 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Wed, 13 Mar 2013 04:30:23 -0300 Subject: [PATCH 0098/1224] Added error messages with line number when using -debug in console --- .../Exceptions/CompilationException.cs | 11 - .../Exceptions/ScriptExecutionException.cs | 11 + src/ScriptCs.Core/FilePreProcessor.cs | 10 +- src/ScriptCs.Core/ScriptCs.Core.csproj | 2 +- src/ScriptCs.Core/ScriptPackSession.cs | 21 +- .../RoslynScriptDebuggerEngine.cs | 16 +- src/ScriptCs/Program.cs | 2 +- .../FileProcessorTests.cs.orig | 476 ++++++++++++++++++ .../RoslynScriptDebuggerEngine.cs | 46 ++ .../RoslynScriptEngineTests.cs | 4 + .../ScriptCs.Engine.Roslyn.Tests.csproj | 3 +- 11 files changed, 580 insertions(+), 22 deletions(-) delete mode 100644 src/ScriptCs.Core/Exceptions/CompilationException.cs create mode 100644 src/ScriptCs.Core/Exceptions/ScriptExecutionException.cs create mode 100644 test/ScriptCs.Core.Tests/FileProcessorTests.cs.orig create mode 100644 test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs diff --git a/src/ScriptCs.Core/Exceptions/CompilationException.cs b/src/ScriptCs.Core/Exceptions/CompilationException.cs deleted file mode 100644 index b239a55c..00000000 --- a/src/ScriptCs.Core/Exceptions/CompilationException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace ScriptCs.Exceptions -{ - public class CompilationException : Exception - { - public CompilationException(string message) : base(message) - { - } - } -} diff --git a/src/ScriptCs.Core/Exceptions/ScriptExecutionException.cs b/src/ScriptCs.Core/Exceptions/ScriptExecutionException.cs new file mode 100644 index 00000000..e6688ad3 --- /dev/null +++ b/src/ScriptCs.Core/Exceptions/ScriptExecutionException.cs @@ -0,0 +1,11 @@ +using System; + +namespace ScriptCs.Exceptions +{ + public class ScriptExecutionException : Exception + { + public ScriptExecutionException(string message) : base(message) + { + } + } +} diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 64484d85..7bb62b1c 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -55,14 +55,16 @@ protected virtual string GenerateRs(ICollection rLines) private string ParseFile(string path, IEnumerable file, ref List usings, ref List rs, ref List loads) { var fileList = file.ToList(); - var firstCode = fileList.FindIndex(i => IsNonDirectiveLine(i)); + var firstCode = fileList.FindIndex(l => IsNonDirectiveLine(l)); + + var firstBody = fileList.FindIndex(l => IsNonDirectiveLine(l) && !IsUsingLine(l)); // add #line before the actual code begins // +1 because we are in a zero indexed list, but line numbers are 1 indexed // we need to keep the original position of the actual line - if (firstCode != -1) + if (firstBody != -1) { - fileList.Insert(firstCode, string.Format(@"#line {0} ""{1}""", firstCode + 1, path)); + fileList.Insert(firstBody, string.Format(@"#line {0} ""{1}""", firstBody + 1, path)); } for (var i = 0; i < fileList.Count; i++) @@ -112,7 +114,7 @@ private string ParseFile(string path, IEnumerable file, ref List private static bool IsNonDirectiveLine(string line) { - return !IsRLine(line) && !IsLoadLine(line) && !IsUsingLine(line) && line.Trim() != string.Empty; + return !IsRLine(line) && !IsLoadLine(line) && line.Trim() != string.Empty; } private static bool IsUsingLine(string line) diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 109637c4..015becfc 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -24,7 +24,7 @@ - + Properties\CommonAssemblyInfo.cs diff --git a/src/ScriptCs.Core/ScriptPackSession.cs b/src/ScriptCs.Core/ScriptPackSession.cs index f5b5ccc9..f729c401 100644 --- a/src/ScriptCs.Core/ScriptPackSession.cs +++ b/src/ScriptCs.Core/ScriptPackSession.cs @@ -20,20 +20,35 @@ public ScriptPackSession(IEnumerable scriptPacks) _namespaces = new List(); } - public IEnumerable ScriptPacks { get { return _scriptPacks; } } - public IEnumerable References { get { return _references; } } - public IEnumerable Namespaces { get { return _namespaces; } } + public IEnumerable ScriptPacks + { + get { return _scriptPacks; } + } + + public IEnumerable References + { + get { return _references; } + } + + public IEnumerable Namespaces + { + get { return _namespaces; } + } public void InitializePacks() { foreach (var s in _scriptPacks) + { s.Initialize(this); + } } public void TerminatePacks() { foreach (var s in _scriptPacks) + { s.Terminate(); + } } void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index feac7755..83b75df1 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reflection; using Roslyn.Scripting; +using ScriptCs.Exceptions; namespace ScriptCs.Engine.Roslyn { @@ -47,7 +48,20 @@ protected override void Execute(string code, Session session) var type = assembly.GetType(CompiledScriptClass); var method = type.GetMethod(CompiledScriptMethod, BindingFlags.Static | BindingFlags.Public); - method.Invoke(null, new[] { session }); + try + { + method.Invoke(null, new[] { session }); + } + catch (Exception e) + { + var message = + string.Format( + "Exception Message: {0} {1}Stack Trace:{2}", + e.InnerException.Message, + Environment.NewLine, + e.InnerException.StackTrace); + throw new ScriptExecutionException(message); + } } } } diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 6bee9869..696c7db3 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -56,7 +56,7 @@ private static void Main(string[] args) executor.Execute(script, paths, scriptPackManager.GetPacks()); } - catch (MissingAssemblyException ex) + catch (Exception ex) { Console.WriteLine(ex.Message); } diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs.orig b/test/ScriptCs.Core.Tests/FileProcessorTests.cs.orig new file mode 100644 index 00000000..93913a57 --- /dev/null +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs.orig @@ -0,0 +1,476 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class FileProcessorTests + { +<<<<<<< HEAD + public class TheProcessFileMethod + { + private List file1 = new List + { + "using System;", + @"Console.WriteLine(""Hello Script 1"");", + @"Console.WriteLine(""Loading Script 2"");", + @"#load ""script2.csx""", + @"Console.WriteLine(""Loaded Script 2"");", + @"Console.WriteLine(""Loading Script 4"");", + @"#load ""script4.csx"";", + @"Console.WriteLine(""Loaded Script 4"");", + @"Console.WriteLine(""Goodbye Script 1"");" + }; + + private List file2 = new List + { + "using System;", + @"Console.WriteLine(""Hello Script 2"");", + @"Console.WriteLine(""Loading Script 3"");", + @"#load ""script3.csx""", + @"Console.WriteLine(""Loaded Script 3"");", + @"Console.WriteLine(""Goodbye Script 2"");" + }; + + private List file3 = new List +======= + public class ProcessFileMethod + { + private List _file1 = new List + { + @"#load ""script2.csx""", + @"#load ""script4.csx"";", + "using System;", + @"Console.WriteLine(""Hello Script 1"");", + @"Console.WriteLine(""Loading Script 2"");", + @"Console.WriteLine(""Loaded Script 2"");", + @"Console.WriteLine(""Loading Script 4"");", + @"Console.WriteLine(""Loaded Script 4"");", + @"Console.WriteLine(""Goodbye Script 1"");" + }; + + private List _file2 = new List + { + "using System;", + @"Console.WriteLine(""Hello Script 2"");", + @"Console.WriteLine(""Loading Script 3"");", + @"#load ""script3.csx""", + @"Console.WriteLine(""Loaded Script 3"");", + @"Console.WriteLine(""Goodbye Script 2"");" + }; + + private readonly List _file3 = new List + { + "using System;", + "using System.Collections.Generic;", + @"Console.WriteLine(""Hello Script 3"");", + @"Console.WriteLine(""Goodbye Script 3"");" + }; + + private readonly List _file4 = new List + { + "using System;", + "using System.Core;", + @"Console.WriteLine(""Hello Script 4"");", + @"Console.WriteLine(""Goodbye Script 4"");" + }; + + private readonly Mock _fileSystem; + + public ProcessFileMethod() + { + _fileSystem = new Mock(); + _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + .Returns(_file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + .Returns(_file2.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) + .Returns(_file3.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + .Returns(_file4.ToArray()); + } + + [Fact] + public void MultipleUsingStatementsShouldProduceDistinctOutput() + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))), Times.Exactly(3)); + Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + } + + [Fact] + public void UsingStateMentsShoulAllBeAtTheTop() +>>>>>>> e46d53e6a34d0ae5aadc5876ae63d9d8af3e278e + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + +<<<<<<< HEAD + private List file4 = new List +======= + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + + Assert.True(lastUsing < firsNotUsing); + } + + [Fact] + public void ShouldNotLoadInlineLoads() +>>>>>>> e46d53e6a34d0ae5aadc5876ae63d9d8af3e278e + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + +<<<<<<< HEAD + private readonly Mock _fileSystem; + + public TheProcessFileMethod() + { + _fileSystem = new Mock(); + _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + .Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + .Returns(file2.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) + .Returns(file3.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + .Returns(file4.ToArray()); + } + + [Fact] + public void MultipleUsingStatementsShouldProduceDistinctOutput() + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))), Times.Exactly(4)); + Assert.Equal(3, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + } + + [Fact] + public void UsingStateMentsShoulAllBeAtTheTop() + { + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + + Assert.True(lastUsing < firsNotUsing); + } + + [Fact] + public void ThreeLoadedFilesShoulAllBeCalledOnce() + { + var processor = new FilePreProcessor(_fileSystem.Object); + processor.ProcessFile("\\script1.csx"); + + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + } + + [Fact] + public void LoadBeforeUsingShouldBeAllowed() + { + var file = new List + { + @"#load ""script4.csx""", + "", + "using System;", + @"Console.WriteLine(""abc"");" + }; +======= + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + } + + [Fact] + public void ShouldNotLoadSameFileTwice() + { + var file = new List + { + @"#load ""script4.csx""", + "using System;", + @"Console.WriteLine(""Hello Script 2"");", + }; + + var fs = new Mock(); + fs.Setup(i => i.NewLine).Returns(Environment.NewLine); + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + .Returns(file.ToArray()); + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + .Returns(_file4.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + } + + [Fact] + public void LoadBeforeUsingShouldBeAllowed() + { + var file = new List + { + @"#load ""script4.csx""", + "", + "using System;", + @"Console.WriteLine(""abc"");" + }; + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); + + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + + splitOutput.Count(x => x.TrimStart(' ').StartsWith("using ")).ShouldEqual(2); + Assert.True(lastUsing < firsNotUsing); + } + + [Fact] + public void ShouldNotBeAllowedToLoadAfterUsing() + { + var file = new List + { + "using System;", + @"Console.WriteLine(""abc"");", + @"#load ""script4.csx""" + }; +>>>>>>> e46d53e6a34d0ae5aadc5876ae63d9d8af3e278e + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); + +<<<<<<< HEAD + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); + var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); + + Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + Assert.True(lastUsing < firsNotUsing); +======= + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + + Assert.Equal(1, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); + Assert.Equal(3, splitOutput.Length); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); +>>>>>>> e46d53e6a34d0ae5aadc5876ae63d9d8af3e278e + } + + [Fact] + public void UsingInCodeDoesNotCountAsUsingImport() + { + var file = new List +<<<<<<< HEAD + { + @"#load ""script4.csx""", + "", + "using System;", + "using System.IO;", + "Console.WriteLine();", + @"using (var stream = new MemoryStream) {", + @"//do stuff", + @"}" + }; + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); + + var splitOutput = output.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var firstNonImportUsing = splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); + var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); + + Assert.True(firstNonImportUsing > firstCodeLine); + } + + [Fact] + public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() + { + // f1 has usings and then loads + var f1 = new List + { + "using System;", + "using System.Diagnostics;", + @"#load ""C:\f2.csx"";", + @"#load ""C:\f3.csx"";", + @"Console.WriteLine(""First line of f1"");", + }; + + // f2 has no usings and multiple loads + var f2 = new List + { + @"#load ""C:\f4.csx"";", + @"#load ""C:\f5.csx"";", + @"Console.WriteLine(""First line of f2"");", + }; + + // f3 has usings and no loads + var f3 = new List + { + @"using System;", + @"using System.Diagnostics;", + @"Console.WriteLine(""First line of f3"");", + }; + + // f4 has no usings and no loads + var f4 = new List + { + @"Console.WriteLine(""First line of f4"");", + }; + + // f5 is no special case, just used to be loaded + var f5 = new List + { + @"using System;", + @"Console.WriteLine(""First line of f5"");", + }; + + _fileSystem.SetupGet(fs => fs.NewLine).Returns(Environment.NewLine); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f1.csx")) + .Returns(f1.ToArray()); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f2.csx")) + .Returns(f2.ToArray()).Verifiable(); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f3.csx")) + .Returns(f3.ToArray()); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f4.csx")) + .Returns(f4.ToArray()); + _fileSystem.Setup(fs => fs.ReadFileLines(@"C:\f5.csx")) + .Returns(f5.ToArray()); + _fileSystem.Setup(fs => fs.IsPathRooted(It.IsAny())).Returns(true); + + var preProcessor = new FilePreProcessor(_fileSystem.Object); + + var file = preProcessor.ProcessFile(@"C:\f1.csx"); + + var fileLines = file.Split(new[]{ Environment.NewLine }, StringSplitOptions.None); + + // using statements go first, after that f4 -> f5 -> f2 -> f3 -> f1 + var line = 0; + fileLines[line++].ShouldEqual("using System;"); + fileLines[line++].ShouldEqual("using System.Diagnostics;"); + + fileLines[line++].ShouldEqual(@"#line 1 ""C:\f4.csx"""); + fileLines[line++].ShouldEqual(f4[0]); + + fileLines[line++].ShouldEqual(@"#line 2 ""C:\f5.csx"""); + fileLines[line++].ShouldEqual(f5[1]); + + fileLines[line++].ShouldEqual(@"#line 3 ""C:\f2.csx"""); + fileLines[line++].ShouldEqual(f2[2]); + + fileLines[line++].ShouldEqual(@"#line 3 ""C:\f3.csx"""); + fileLines[line++].ShouldEqual(f3[2]); + + fileLines[line++].ShouldEqual(@"#line 5 ""C:\f1.csx"""); + fileLines[line].ShouldEqual(f1[4]); +======= + { + @"#load ""script4.csx""", + "", + "using System;", + "using System.IO;", + "Console.WriteLine();", + @"using (var stream = new MemoryStream) {", + @"//do stuff", + @"}" + }; + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\file.csx"); + + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var firstNonImportUsing = + splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); + var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); + + Assert.True(firstNonImportUsing > firstCodeLine); + } + + [Fact] + public void ShouldHaveReferencesOnTop() + { + var file1 = new List + { + @"#r ""My.dll""", + @"#load ""script2.csx""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + var fs = new Mock(); + fs.Setup(i => i.NewLine).Returns(Environment.NewLine); + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))).Returns(file1.ToArray()); + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))).Returns(_file2.ToArray()); + + var processor = new FilePreProcessor(fs.Object); + var output = processor.ProcessFile("\\script1.csx"); + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None).ToList(); + + var lastR = splitOutput.FindLastIndex(line => line.StartsWith("#r ")); + var firstNotR = splitOutput.FindIndex(line => !line.StartsWith("#r ")); + + lastR.ShouldNotEqual(-1); + Assert.True(lastR < firstNotR); + } + + [Fact] + public void ShouldHaveReferencesFromAllFiles() + { + var file1 = new List + { + @"#r ""My.dll""", + @"#load ""scriptX.csx""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + var file2 = new List + { + @"#r ""My2.dll""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + .Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\scriptX.csx"))) + .Returns(file2.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object); + var output = processor.ProcessFile("\\script1.csx"); + + var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + splitOutput.Count(line => line.StartsWith("#r ")).ShouldEqual(2); +>>>>>>> e46d53e6a34d0ae5aadc5876ae63d9d8af3e278e + } + } + } +} diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs new file mode 100644 index 00000000..e418cf92 --- /dev/null +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs @@ -0,0 +1,46 @@ +using System; +using System.Linq; +using Moq; +using ScriptCs.Contracts; +using ScriptCs.Engine.Roslyn; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + using ScriptCs.Exceptions; + + public class RoslynScriptDebuggerEngineTests + { + private static RoslynScriptDebuggerEngine CreateScriptEngine( + Mock scriptHostFactory = null) + { + scriptHostFactory = scriptHostFactory ?? new Mock(); + + return new RoslynScriptDebuggerEngine(scriptHostFactory.Object); + } + + public class TheExecuteMethod + { + [Fact] + public void ShouldThrowExceptionThrownByScriptWhenErrorOccurs() + { + var code = string.Format( + "{0}{1}{2}", + "using System;", + Environment.NewLine, + @"throw new InvalidOperationException(""InvalidOperationExceptionMessage."");"); + + var scriptEngine = CreateScriptEngine(); + + var exception = Assert.Throws( + () => + scriptEngine.Execute( + code, Enumerable.Empty(), new ScriptPackSession(Enumerable.Empty()))); + + exception.Message.ShouldContain("line 2"); + exception.Message.ShouldContain("Exception Message: InvalidOperationExceptionMessage."); + } + } + } +} diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 6482bfac..49bc5827 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -4,10 +4,13 @@ using Moq; using ScriptCs.Contracts; using ScriptCs.Engine.Roslyn; +using Should; using Xunit; namespace ScriptCs.Tests { + using Roslyn.Scripting.CSharp; + public class RoslynScriptEngineTests { private static RoslynScriptEngine CreateScriptEngine( @@ -44,6 +47,7 @@ public void ShouldCreateScriptHostWithContexts() scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); } + } } } \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj index d6f89a0c..3a3c2c41 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj @@ -33,6 +33,7 @@ + @@ -54,4 +55,4 @@ - + \ No newline at end of file From 4e3340d7720482d6a8d91c5584b0bbe2cf6832a5 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 13 Mar 2013 01:49:40 -0700 Subject: [PATCH 0099/1224] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 324dcd6f..80329982 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # scriptcs ## Why should you care? -Write C# apps with a text editor, nuget and the power of Roslyn! +Write C# apps with a text editor, nuget and the power of [Roslyn] (http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx)! **Note**: *Roslyn is a pre-release CTP and currently an unsupported technology. As such there may be changes in Roslyn itself that could impact this project. Please bear that in mind when using scriptcs* From 86c193893cae36d9b102696c6f6cb2f8808aadf3 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 13 Mar 2013 09:49:51 +0100 Subject: [PATCH 0100/1224] Added #r and wrapped app in STA thread --- samples/wpf/app.csx | 9 ++++++++- samples/wpf/utilities.csx | 11 ++++++++++- samples/wpf/views.csx | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/samples/wpf/app.csx b/samples/wpf/app.csx index 57d59f0f..51a4e86c 100644 --- a/samples/wpf/app.csx +++ b/samples/wpf/app.csx @@ -1,3 +1,9 @@ +#r "PresentationCore" +#r "PresentationFramework" +#r "WindowsBase" +#r "System.Xaml" +#r "System.Xml" + #load utilities.csx #load mvvm.csx @@ -6,6 +12,7 @@ using System; using System.Windows; +using System.Threading; public class App : Application { @@ -23,4 +30,4 @@ public class App : Application } } -new App().Run(); +Utilities.RunInSTAThread(() => new App().Run()); \ No newline at end of file diff --git a/samples/wpf/utilities.csx b/samples/wpf/utilities.csx index 2e6f6607..f3f24725 100644 --- a/samples/wpf/utilities.csx +++ b/samples/wpf/utilities.csx @@ -1,9 +1,10 @@ using System.IO; +using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; -public static class XamlUtility +public static class Utilities { public static void LoadXaml(ContentControl contentControl, string xamlFile) { @@ -12,4 +13,12 @@ public static class XamlUtility contentControl.Content = XamlReader.Load(fileStream) as DependencyObject; } } + + public static void RunInSTAThread(ThreadStart threadStart) + { + var thread = new Thread(threadStart); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + thread.Join(); + } } \ No newline at end of file diff --git a/samples/wpf/views.csx b/samples/wpf/views.csx index 79bdd685..159b24db 100644 --- a/samples/wpf/views.csx +++ b/samples/wpf/views.csx @@ -2,6 +2,6 @@ public class CalculatorView : Window { public CalculatorView() { - XamlUtility.LoadXaml(this, "CalculatorView.xaml"); + Utilities.LoadXaml(this, "CalculatorView.xaml"); } } \ No newline at end of file From dfd6a9767120b3f44f5eba38dae01b84d5c6cdcc Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 13 Mar 2013 16:45:16 -0400 Subject: [PATCH 0101/1224] Add CommonAssemblyInfo and CommonVersionInfo to the ScriptCs.Engine.Roslyn projects --- common/CommonVersionInfo.cs | 6 +++- .../Properties/AssemblyInfo.cs | 34 +------------------ .../ScriptCs.Engine.Roslyn.csproj | 8 ++++- .../Properties/AssemblyInfo.cs | 32 ----------------- .../ScriptCs.Engine.Roslyn.Tests.csproj | 7 ++++ 5 files changed, 20 insertions(+), 67 deletions(-) diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index ce7aeb47..590a13eb 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,5 +1,9 @@ using System.Reflection; +/** + * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the + * contents of 'build\ScriptCs.Version.props'. + **/ + [assembly: AssemblyVersion("0.0.0")] -[assembly: AssemblyFileVersion("0.0.0.0")] [assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/Properties/AssemblyInfo.cs b/src/ScriptCs.Engine.Roslyn/Properties/AssemblyInfo.cs index 275c7db4..75a66a88 100644 --- a/src/ScriptCs.Engine.Roslyn/Properties/AssemblyInfo.cs +++ b/src/ScriptCs.Engine.Roslyn/Properties/AssemblyInfo.cs @@ -1,36 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. [assembly: AssemblyTitle("ScriptCs.Engine.Roslyn")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScriptCs.Engine.Roslyn")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("0783d2c9-c21b-4281-a195-f0f83fc4936f")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyDescription("ScriptCs.Engine.Roslyn provides a Roslyn-based script engine for scriptcs.")] diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 12096ac6..7dd7faa3 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -6,7 +6,7 @@ Library ScriptCs.Engine.Roslyn ScriptCs.Engine.Roslyn - true + ..\..\ @@ -25,6 +25,12 @@ + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Engine.Roslyn.Tests/Properties/AssemblyInfo.cs b/test/ScriptCs.Engine.Roslyn.Tests/Properties/AssemblyInfo.cs index bdf4591f..5852ca04 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/Properties/AssemblyInfo.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/Properties/AssemblyInfo.cs @@ -1,36 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. [assembly: AssemblyTitle("ScriptCs.Engine.Roslyn")] [assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScriptCs.Engine.Roslyn")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("16063b38-8d89-4cec-abd2-45102e1905df")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj index 3a3c2c41..4f9bc964 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj @@ -6,6 +6,7 @@ Library ScriptCs.Tests ScriptCs.Engine.Roslyn.Tests + ..\..\ @@ -32,6 +33,12 @@ + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + From d39eaec311922c460d7231ac8a85d1c68d2cbbd6 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 13 Mar 2013 16:46:07 -0400 Subject: [PATCH 0102/1224] Add a nuspec file to the ScriptCs.Engine.Roslyn project --- build/Build.proj | 8 ++++++-- .../Properties/ScriptCs.Engine.Roslyn.nuspec | 20 +++++++++++++++++++ .../ScriptCs.Engine.Roslyn.csproj | 3 ++- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/ScriptCs.Engine.Roslyn/Properties/ScriptCs.Engine.Roslyn.nuspec diff --git a/build/Build.proj b/build/Build.proj index 9f75a8f0..6d856d14 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -25,6 +25,7 @@ + @@ -50,8 +51,11 @@ - - + + + + + diff --git a/src/ScriptCs.Engine.Roslyn/Properties/ScriptCs.Engine.Roslyn.nuspec b/src/ScriptCs.Engine.Roslyn/Properties/ScriptCs.Engine.Roslyn.nuspec new file mode 100644 index 00000000..4d2cccb8 --- /dev/null +++ b/src/ScriptCs.Engine.Roslyn/Properties/ScriptCs.Engine.Roslyn.nuspec @@ -0,0 +1,20 @@ + + + + ScriptCs.Engine.Roslyn + 0.0.0 + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md + http://scriptcs.net + http://www.gravatar.com/avatar/5c754f646971d8bc800b9d4057931938.png?s=120 + ScriptCs.Engine.Roslyn provides a Roslyn-based script engine for scriptcs. + roslyn csx script scriptcs + + + + + + + + \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 7dd7faa3..78576b95 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -40,6 +40,7 @@ + @@ -53,4 +54,4 @@ - + \ No newline at end of file From f0cc67a99542f4e4a9b64592dadcf6d06d2da0ce Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 13 Mar 2013 20:07:36 -0300 Subject: [PATCH 0103/1224] Update README.md Add links to Google Groups and JabbR --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 80329982..b9d2d054 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,9 @@ Read our [Contribution Guidelines](https://github.com/scriptcs/scriptcs/blob/mas * Justin Rusbatch ([@jrusbatch](https://twitter.com/jrusbatch)) * Filip Wojcieszyn ([@filip_woj](https://twitter.com/filip_woj)) +## Community +Want to chat? In addition to Twitter, you can find us on [Google Groups](https://groups.google.com/forum/?fromgroups#!forum/scriptcs) and [JabbR](https://jabbr.net/#/rooms/scriptcs)! + ## License [Apache 2 License](https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md) From 5a385332ea35ad06393033177a192fd7376b312f Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 13 Mar 2013 20:07:36 -0300 Subject: [PATCH 0104/1224] Update README.md Add links to Google Groups and JabbR --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index fe09b69f..13047d96 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ Read our [Contribution Guidelines](https://github.com/scriptcs/scriptcs/blob/mas * Justin Rusbatch ([@jrusbatch](https://twitter.com/jrusbatch)) * Filip Wojcieszyn ([@filip_woj](https://twitter.com/filip_woj)) +## Community +Want to chat? In addition to Twitter, you can find us on [Google Groups](https://groups.google.com/forum/?fromgroups#!forum/scriptcs) and [JabbR](https://jabbr.net/#/rooms/scriptcs)! + ## License [Apache 2 License](https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md) From 314a5313f43f0f949fc4089c81f4cb89dabaa0b1 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 13 Mar 2013 22:00:03 -0300 Subject: [PATCH 0105/1224] Update README.md Add a link to the samples repository --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b9d2d054..8ba6335d 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,9 @@ This will launch a web api host. ## How it works scriptcs relies on Rosyln for loading loose C# script files. It will automatically discover nuget packages local to the app and load the binaries. +## Samples +You can find additional samples for scriptcs in our [samples repository](https://github.com/scriptcs/scriptcs-samples). + ## What's next * Adding support for pluggable recipe "packs" for different frameworks. From 46a5c30728ba442ae6654a8c2a669bb40c0304e2 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 13 Mar 2013 21:03:37 -0400 Subject: [PATCH 0106/1224] Remove samples directory --- .../servicestackhost/ServiceStack-server.csx | 38 ---------------- samples/servicestackhost/packages.config | 8 ---- samples/webapihost/packages.config | 8 ---- samples/webapihost/server.csx | 43 ------------------- 4 files changed, 97 deletions(-) delete mode 100644 samples/servicestackhost/ServiceStack-server.csx delete mode 100644 samples/servicestackhost/packages.config delete mode 100644 samples/webapihost/packages.config delete mode 100644 samples/webapihost/server.csx diff --git a/samples/servicestackhost/ServiceStack-server.csx b/samples/servicestackhost/ServiceStack-server.csx deleted file mode 100644 index ca3430cc..00000000 --- a/samples/servicestackhost/ServiceStack-server.csx +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using ServiceStack.ServiceInterface; -using ServiceStack.WebHost.Endpoints; -using System.Reflection; - -public class Hello { - public string Name { get; set; } -} - -public class HelloResponse { - public string Result { get; set; } -} - -public class HelloService : Service -{ - public object Any(Hello request) - { - return new HelloResponse { Result = "Hello, " + request.Name }; - } -} - -public class AppHost : AppHostHttpListenerBase { - public AppHost() : base("StarterTemplate HttpListener", Assembly.GetExecutingAssembly()) { } - - public override void Configure(Funq.Container container) { - Routes - .Add("/hello") - .Add("/hello/{Name}"); - } -} - -var port = "http://*:999/"; -var appHost = new AppHost(); -appHost.Init(); -appHost.Start(port); - -Console.WriteLine("listening on {0}", port); -Console.ReadKey(); \ No newline at end of file diff --git a/samples/servicestackhost/packages.config b/samples/servicestackhost/packages.config deleted file mode 100644 index ea25110a..00000000 --- a/samples/servicestackhost/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/samples/webapihost/packages.config b/samples/webapihost/packages.config deleted file mode 100644 index 24e17745..00000000 --- a/samples/webapihost/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/samples/webapihost/server.csx b/samples/webapihost/server.csx deleted file mode 100644 index e694a72f..00000000 --- a/samples/webapihost/server.csx +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.IO; -using System.Web.Http; -using System.Web.Http.SelfHost; -using System.Web.Http.Dispatcher; - -public class TestController : System.Web.Http.ApiController { - - public string Get() { - return "Hello world!"; - } -} - -public class ControllerResolver : DefaultHttpControllerTypeResolver { - - public override ICollection GetControllerTypes(IAssembliesResolver assembliesResolver) { - - var types = Assembly.GetExecutingAssembly().GetTypes(); - return types.Where(x => typeof(System.Web.Http.Controllers.IHttpController).IsAssignableFrom(x)).ToList(); - } - -} - -var address = "http://localhost:8080"; -var conf = new HttpSelfHostConfiguration(new Uri(address)); -conf.Services.Replace(typeof(IHttpControllerTypeResolver), new ControllerResolver()); - -conf.Routes.MapHttpRoute(name: "DefaultApi", - routeTemplate: "api/{controller}/{id}", - defaults: new { id = RouteParameter.Optional } -); - -Console.WriteLine(Assembly.GetAssembly(typeof(TestController)).FullName); -Console.WriteLine(Assembly.GetAssembly(typeof(TestController)).IsDynamic); - -var server = new HttpSelfHostServer(conf); -server.OpenAsync().Wait(); -Console.WriteLine("Listening..."); -Console.ReadKey(); \ No newline at end of file From bb1c1ad6a14691e4f8cc841b0dfedf053dbcddf9 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 13 Mar 2013 21:03:37 -0400 Subject: [PATCH 0107/1224] Removing samples directory --- samples/fluentautomation/FluentAutomation.csx | 39 ------ samples/fluentautomation/README.md | 13 -- samples/fluentautomation/TestKnockoutJS.csx | 26 ---- samples/fluentautomation/packages.config | 8 -- samples/nancy/README.md | 23 ---- samples/nancy/bootstrapper.csx | 25 ---- .../nancy/customroutedescriptionprovider.csx | 7 - samples/nancy/module.csx | 9 -- samples/nancy/packages.config | 7 - samples/nancy/pathprovider.csx | 7 - samples/nancy/start.csx | 27 ---- samples/nancy/views/index.html | 45 ------- samples/referencing-scripts/start.csx | 16 --- samples/referencing-scripts/utility.csx | 15 --- samples/servicestackhost/models.csx | 7 - samples/servicestackhost/packages.config | 8 -- samples/servicestackhost/service.csx | 9 -- samples/servicestackhost/start.csx | 24 ---- samples/signalr-livereload/README.md | 38 ------ samples/signalr-livereload/broadcaster.csx | 96 -------------- .../signalr-livereload/jsonconfiguration.csx | 20 --- samples/signalr-livereload/models.csx | 6 - samples/signalr-livereload/packages.config | 5 - .../signalr-livereload/signalr.livereload.csx | 37 ------ samples/signalr-livereload/usings.csx | 9 -- samples/webapihost/packages.config | 8 -- samples/webapihost/server.csx | 43 ------ samples/wpf/CalculatorView.xaml | 47 ------- samples/wpf/app.csx | 33 ----- samples/wpf/mvvm.csx | 49 ------- samples/wpf/utilities.csx | 24 ---- samples/wpf/viewmodels.csx | 124 ------------------ samples/wpf/views.csx | 7 - 33 files changed, 861 deletions(-) delete mode 100644 samples/fluentautomation/FluentAutomation.csx delete mode 100644 samples/fluentautomation/README.md delete mode 100644 samples/fluentautomation/TestKnockoutJS.csx delete mode 100644 samples/fluentautomation/packages.config delete mode 100644 samples/nancy/README.md delete mode 100644 samples/nancy/bootstrapper.csx delete mode 100644 samples/nancy/customroutedescriptionprovider.csx delete mode 100644 samples/nancy/module.csx delete mode 100644 samples/nancy/packages.config delete mode 100644 samples/nancy/pathprovider.csx delete mode 100644 samples/nancy/start.csx delete mode 100644 samples/nancy/views/index.html delete mode 100644 samples/referencing-scripts/start.csx delete mode 100644 samples/referencing-scripts/utility.csx delete mode 100644 samples/servicestackhost/models.csx delete mode 100644 samples/servicestackhost/packages.config delete mode 100644 samples/servicestackhost/service.csx delete mode 100644 samples/servicestackhost/start.csx delete mode 100644 samples/signalr-livereload/README.md delete mode 100644 samples/signalr-livereload/broadcaster.csx delete mode 100644 samples/signalr-livereload/jsonconfiguration.csx delete mode 100644 samples/signalr-livereload/models.csx delete mode 100644 samples/signalr-livereload/packages.config delete mode 100644 samples/signalr-livereload/signalr.livereload.csx delete mode 100644 samples/signalr-livereload/usings.csx delete mode 100644 samples/webapihost/packages.config delete mode 100644 samples/webapihost/server.csx delete mode 100644 samples/wpf/CalculatorView.xaml delete mode 100644 samples/wpf/app.csx delete mode 100644 samples/wpf/mvvm.csx delete mode 100644 samples/wpf/utilities.csx delete mode 100644 samples/wpf/viewmodels.csx delete mode 100644 samples/wpf/views.csx diff --git a/samples/fluentautomation/FluentAutomation.csx b/samples/fluentautomation/FluentAutomation.csx deleted file mode 100644 index e392f0c7..00000000 --- a/samples/fluentautomation/FluentAutomation.csx +++ /dev/null @@ -1,39 +0,0 @@ -using FluentAutomation; -using FluentAutomation.Interfaces; -using System; -using System.IO; -using System.Reflection; - -private static INativeActionSyntaxProvider I = null; - -public static void Bootstrap(string browserName) -{ - MethodInfo bootstrapMethod = null; - ParameterInfo[] bootstrapParams = null; - - MethodInfo[] methods = typeof(T).GetMethods(BindingFlags.Static | BindingFlags.Public); - foreach (var methodInfo in methods) - { - if (methodInfo.Name.Equals("Bootstrap")) - { - bootstrapMethod = methodInfo; - bootstrapParams = methodInfo.GetParameters(); - if (bootstrapParams.Length == 1) - { - break; - } - } - } - - var browserEnumValue = Enum.Parse(bootstrapParams[0].ParameterType, browserName); - bootstrapMethod.Invoke(null, new object[] { browserEnumValue }); - - I = new FluentTest().I; - - // hack to move drivers into bin so they can be located by Selenium (only prob on scriptcs atm) - foreach (var driver in Directory.GetFiles(Environment.CurrentDirectory, "*.exe")) - { - var newFileName = Path.Combine(Environment.CurrentDirectory, "bin", Path.GetFileName(driver)); - if (!File.Exists(newFileName)) File.Move(driver, newFileName); - } -} diff --git a/samples/fluentautomation/README.md b/samples/fluentautomation/README.md deleted file mode 100644 index 0cf07cc5..00000000 --- a/samples/fluentautomation/README.md +++ /dev/null @@ -1,13 +0,0 @@ -*Instructions* - -- Install nuget somewhere in your path. -- Install scriptcs somewhere in your path. -- Download this gist to a folder. -- From that directory, run 'nuget install FluentAutomation.SeleniumWebDriver -o packages' -- Then run 'scriptcs TestKnockoutJS.csx' - -*Comments* - -This could be really really good from a testing standpoint. One file per test-case, with no extra bits necessary feels awesome. - -Also.. Don't forget to call I.Dispose() at the end of the script or the browser will just hang around after the test. I think we'll do some refactoring to make this a bit smarter in this context, as well as eliminate the need for the reflection in Bootstrap() in FluentAutomation.csx \ No newline at end of file diff --git a/samples/fluentautomation/TestKnockoutJS.csx b/samples/fluentautomation/TestKnockoutJS.csx deleted file mode 100644 index a2a54550..00000000 --- a/samples/fluentautomation/TestKnockoutJS.csx +++ /dev/null @@ -1,26 +0,0 @@ -#load "FluentAutomation.csx" - -Bootstrap("InternetExplorer"); - -I.Open("http://knockoutjs.com/examples/cartEditor.html"); -I.Select("Motorcycles").From(".liveExample tr select:eq(0)"); // Select by value/text -I.Select(2).From(".liveExample tr select:eq(1)"); // Select by index -I.Enter(6).In(".liveExample td.quantity input:eq(0)"); -I.Expect.Text("$197.70").In(".liveExample tr span:eq(1)"); - -// add second product -I.Click(".liveExample button:eq(0)"); -I.Select(1).From(".liveExample tr select:eq(2)"); -I.Select(4).From(".liveExample tr select:eq(3)"); -I.Enter(8).In(".liveExample td.quantity input:eq(1)"); -I.Expect.Text("$788.64").In(".liveExample tr span:eq(3)"); - -// validate totals -I.Expect.Text("$986.34").In("p.grandTotal span"); - -// remove first product -I.Click(".liveExample a:eq(0)"); - -// validate new total -I.WaitUntil(() => I.Expect.Text("$788.64").In("p.grandTotal span")); -I.Dispose(); diff --git a/samples/fluentautomation/packages.config b/samples/fluentautomation/packages.config deleted file mode 100644 index 46e0577d..00000000 --- a/samples/fluentautomation/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/samples/nancy/README.md b/samples/nancy/README.md deleted file mode 100644 index 132597e3..00000000 --- a/samples/nancy/README.md +++ /dev/null @@ -1,23 +0,0 @@ -Demo of the [Nancy](http://nancyfx.org) framework running on [ScriptCS](https://github.com/scriptcs/scriptcs) - Awesome stuff! - -## Usage -Make sure _ScriptCS.exe_ in in your path and then type `scriptcs start.csx` and browse `http://localhost:1234/` in order to have Nancy server you a view. - -## Note -Nancy relies heavily on assembly scanning to compose the framework at runtime and to "light up" featured. Due to the fact that ScriptCS compiled into a _dynamic assembly_ and because you cannot use _GetExportedTypes_ on a _dynamic assembly_, you are required to provide a bit of customization in order for Nancy to function correctly. - -The following customizations have been included in this demo - -* Implemented a custom _IRootPathProvider_ to have the application set its root outside the bin folder, so that views can be located correctly - -* Implemented a custom _IRouteDescriptionProvider_ that simply returns an empty string. The default implementation would use assembly scanning - -* Use the _Nancy.Bootstrappers.Autofac_ because the default bootstrapper (which is based on _TinyIoC_) uses assembly scanning which is also affected by the limitations of _GetExportedTypes_ on a _dynamic assembly_ - -* Explicitly set _NancyBootstrapperLocator.Bootstrapper_ to an instance of the custom bootstrapper. Normally you would never assign this, but (again) this is due to the issues with assembly scanning - -* Override the _Module_ property, of the bootstrapper, to explicitly tell Nancy which module to use. Modules can't automatically be discovered due to the scanning limitations - -Hopefully these things will not be required in later releases of _ScriptCS_, but as it stands, it serves as a great testament on how Nancy can be modified, without changing a single line of code in the framework, to make it run in any environment! - --- The Nancy team \ No newline at end of file diff --git a/samples/nancy/bootstrapper.csx b/samples/nancy/bootstrapper.csx deleted file mode 100644 index 88aaadc8..00000000 --- a/samples/nancy/bootstrapper.csx +++ /dev/null @@ -1,25 +0,0 @@ -public class Bootstrapper : AutofacNancyBootstrapper -{ - protected override IEnumerable Modules - { - get - { - return new [] { - new ModuleRegistration(typeof(IndexModule), typeof(IndexModule).FullName) - }; - } - } - - protected override NancyInternalConfiguration InternalConfiguration - { - get - { - return NancyInternalConfiguration.WithOverrides(x => x.RouteDescriptionProvider = typeof(CustomRouteDescriptionProvider)); - } - } - - protected override IRootPathProvider RootPathProvider - { - get { return new PathProvider(); } - } -} \ No newline at end of file diff --git a/samples/nancy/customroutedescriptionprovider.csx b/samples/nancy/customroutedescriptionprovider.csx deleted file mode 100644 index 920ba177..00000000 --- a/samples/nancy/customroutedescriptionprovider.csx +++ /dev/null @@ -1,7 +0,0 @@ -public class CustomRouteDescriptionProvider : IRouteDescriptionProvider -{ - public string GetDescription(INancyModule module, string path) - { - return string.Empty; - } -} \ No newline at end of file diff --git a/samples/nancy/module.csx b/samples/nancy/module.csx deleted file mode 100644 index 830772db..00000000 --- a/samples/nancy/module.csx +++ /dev/null @@ -1,9 +0,0 @@ -public class IndexModule : NancyModule -{ - public IndexModule(IRootPathProvider provider) - { - Get["/"] = x => { - return View["index"]; // "Nancy running on ScriptCS!"; - }; - } -} \ No newline at end of file diff --git a/samples/nancy/packages.config b/samples/nancy/packages.config deleted file mode 100644 index fc9895eb..00000000 --- a/samples/nancy/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/samples/nancy/pathprovider.csx b/samples/nancy/pathprovider.csx deleted file mode 100644 index 9b11d03d..00000000 --- a/samples/nancy/pathprovider.csx +++ /dev/null @@ -1,7 +0,0 @@ -public class PathProvider : IRootPathProvider -{ - public string GetRootPath() - { - return Path.Combine("..\\..\\", Environment.CurrentDirectory); - } -} \ No newline at end of file diff --git a/samples/nancy/start.csx b/samples/nancy/start.csx deleted file mode 100644 index 7e3ff4a8..00000000 --- a/samples/nancy/start.csx +++ /dev/null @@ -1,27 +0,0 @@ -#load "module.csx" -#load "bootstrapper.csx" -#load "pathprovider.csx" -#load "customroutedescriptionprovider.csx" - -using System; -using System.Collections.Generic; -using System.IO; -using Autofac; -using Nancy; -using Nancy.Bootstrapper; -using Nancy.Bootstrappers.Autofac; -using Nancy.Hosting.Self; -using Nancy.Routing; - -NancyBootstrapperLocator.Bootstrapper = new Bootstrapper(); - -var adress = "http://localhost:1234/"; - -var host = new NancyHost(new Uri(adress)); -host.Start(); - -Console.WriteLine("Nancy is running at " + adress); -Console.WriteLine("Press any key to end"); -Console.ReadKey(); - -host.Stop(); \ No newline at end of file diff --git a/samples/nancy/views/index.html b/samples/nancy/views/index.html deleted file mode 100644 index 9b3bcd7e..00000000 --- a/samples/nancy/views/index.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - Nancy + ScriptCS demo - - - - - - - - - -
- - Nancy logo - -

Amazing! NANCY is
running on
SCRIPTCS!

- for more information visit nancyfx.org -
- - - \ No newline at end of file diff --git a/samples/referencing-scripts/start.csx b/samples/referencing-scripts/start.csx deleted file mode 100644 index 1c5447cd..00000000 --- a/samples/referencing-scripts/start.csx +++ /dev/null @@ -1,16 +0,0 @@ -#load "utility.csx" - -using System; - -var time = PerformanceUtilities.ExecutionTime(() => -{ - var total = 0; - for (int i = 0; i < 10000; i++) - { - total += i; - Console.WriteLine("Iteration: {0}, Running total: {1}", i, total); - } -}); - -Console.WriteLine("Loop execution took: {0}", time); -Console.ReadKey(); \ No newline at end of file diff --git a/samples/referencing-scripts/utility.csx b/samples/referencing-scripts/utility.csx deleted file mode 100644 index ae430ada..00000000 --- a/samples/referencing-scripts/utility.csx +++ /dev/null @@ -1,15 +0,0 @@ -using System.Diagnostics; - -public class PerformanceUtilities -{ - public static long ExecutionTime(Action action) - { - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - action(); - - stopwatch.Stop(); - return stopwatch.ElapsedMilliseconds; - } -} \ No newline at end of file diff --git a/samples/servicestackhost/models.csx b/samples/servicestackhost/models.csx deleted file mode 100644 index 54ef8811..00000000 --- a/samples/servicestackhost/models.csx +++ /dev/null @@ -1,7 +0,0 @@ -public class Hello { - public string Name { get; set; } -} - -public class HelloResponse { - public string Result { get; set; } -} \ No newline at end of file diff --git a/samples/servicestackhost/packages.config b/samples/servicestackhost/packages.config deleted file mode 100644 index ea25110a..00000000 --- a/samples/servicestackhost/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/samples/servicestackhost/service.csx b/samples/servicestackhost/service.csx deleted file mode 100644 index 78750053..00000000 --- a/samples/servicestackhost/service.csx +++ /dev/null @@ -1,9 +0,0 @@ -using ServiceStack.ServiceInterface; - -public class HelloService : Service -{ - public object Any(Hello request) - { - return new HelloResponse { Result = "Hello, " + request.Name }; - } -} diff --git a/samples/servicestackhost/start.csx b/samples/servicestackhost/start.csx deleted file mode 100644 index 3fe89b81..00000000 --- a/samples/servicestackhost/start.csx +++ /dev/null @@ -1,24 +0,0 @@ -#load "models.csx" -#load "service.csx" - -using System; -using ServiceStack.WebHost.Endpoints; -using System.Reflection; - -public class AppHost : AppHostHttpListenerBase { - public AppHost() : base("StarterTemplate HttpListener", Assembly.GetExecutingAssembly()) { } - - public override void Configure(Funq.Container container) { - Routes - .Add("/hello") - .Add("/hello/{Name}"); - } -} - -var port = "http://*:999/"; -var appHost = new AppHost(); -appHost.Init(); -appHost.Start(port); - -Console.WriteLine("listening on {0}", port); -Console.ReadKey(); \ No newline at end of file diff --git a/samples/signalr-livereload/README.md b/samples/signalr-livereload/README.md deleted file mode 100644 index b1332296..00000000 --- a/samples/signalr-livereload/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# SignalR Live Reload # - -In *your* project that uses SignalR, add the following hub: - - [HubName("liveReload")] - public class LiveReloadHub : Hub - { - public void ReloadAllClients() - { - Clients.Others.reload(); - } - } - -Then, add the relevant markup to your Razor layout: - - - - - - -## Running the Live Reloader ## - -1. Run `nuget install -o packages` to restore the packages listed in `packages.config`. -2. Run `scriptcs signalr.livereload.csx` -3. Edit `config.json` and fill in the blanks. -4. Run `scriptcs signalr.livereload.csx` again. diff --git a/samples/signalr-livereload/broadcaster.csx b/samples/signalr-livereload/broadcaster.csx deleted file mode 100644 index 20d3a6cd..00000000 --- a/samples/signalr-livereload/broadcaster.csx +++ /dev/null @@ -1,96 +0,0 @@ -public class LiveReloadBroadcaster -{ - private bool _initialized; - private string _path; - private string[] _extensions; - private string[] _fileExtensions = { ".cshtml", ".js", ".css", ".html" }; - private FileSystemWatcher _fileSystemWatcher; - private HubConnection _connection; - private IHubProxy _liveReloadHub; - - public LiveReloadBroadcaster(string server, string path, string[] extensions) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - _path = Path.GetFullPath(path); - - if (!Directory.Exists(_path)) - { - throw new DirectoryNotFoundException("Could not find " + _path); - } - - _fileExtensions = extensions; - _fileSystemWatcher = new FileSystemWatcher(_path); - _fileSystemWatcher.IncludeSubdirectories = true; - _fileSystemWatcher.Changed += FileSystemChanged; - - _connection = new HubConnection(server); - _connection.Closed += ConnectionClosed; - _connection.Error += ConnectionError; - _connection.Reconnected += ConnectionReconnected; - _liveReloadHub = _connection.CreateHubProxy("liveReload"); - } - - public void ConnectionClosed() - { - Console.WriteLine("Connection closed."); - } - - public void ConnectionError(Exception ex) - { - Console.WriteLine(ex.Message); - } - - public void ConnectionReconnected() - { - Console.WriteLine("Reconnected."); - } - - public void Start() - { - _fileSystemWatcher.EnableRaisingEvents = true; - - _connection.Start().ContinueWith(task => - { - if (task.IsFaulted) - { - Console.WriteLine("There was an error opening the connection:{0}", - task.Exception.GetBaseException()); - } - else - { - Console.WriteLine("Connected"); - } - - }).Wait(); - } - - public void Stop() - { - _fileSystemWatcher.EnableRaisingEvents = false; - } - - public void FileSystemChanged(object sender, FileSystemEventArgs e) - { - if (!_fileExtensions.Contains(Path.GetExtension(e.FullPath))) - { - return; - } - - _liveReloadHub.Invoke("ReloadAllClients").ContinueWith(task => - { - if (task.IsFaulted) - { - Console.WriteLine("There was an error calling send: {0}", - task.Exception.GetBaseException()); - } - else - { - Console.WriteLine(task.Result); - } - }); - } -} diff --git a/samples/signalr-livereload/jsonconfiguration.csx b/samples/signalr-livereload/jsonconfiguration.csx deleted file mode 100644 index aeb82a54..00000000 --- a/samples/signalr-livereload/jsonconfiguration.csx +++ /dev/null @@ -1,20 +0,0 @@ -public class JsonConfiguration -{ - public static bool Exists(string name) - { - return File.Exists(name); - } - - public static TConfigFile Get(string name) - { - var contents = File.ReadAllText(name); - var config = JsonConvert.DeserializeObject(contents); - return config; - } - - public static void Put(string name, TConfigFile instance) - { - var contents = JsonConvert.SerializeObject(instance, Formatting.Indented); - File.WriteAllText(name, contents); - } -} \ No newline at end of file diff --git a/samples/signalr-livereload/models.csx b/samples/signalr-livereload/models.csx deleted file mode 100644 index e5af5204..00000000 --- a/samples/signalr-livereload/models.csx +++ /dev/null @@ -1,6 +0,0 @@ -public class LiveReloadConfig -{ - public string Server { get; set; } - public string Path { get; set ; } - public string[] Extensions { get; set; } -} diff --git a/samples/signalr-livereload/packages.config b/samples/signalr-livereload/packages.config deleted file mode 100644 index 9db4ffcf..00000000 --- a/samples/signalr-livereload/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/samples/signalr-livereload/signalr.livereload.csx b/samples/signalr-livereload/signalr.livereload.csx deleted file mode 100644 index 65efdca7..00000000 --- a/samples/signalr-livereload/signalr.livereload.csx +++ /dev/null @@ -1,37 +0,0 @@ -#load "usings.csx" -#load "models.csx" -#load "broadcaster.csx" -#load "jsonconfiguration.csx" - -const string ConfigFileName = "config.json"; - -if (!JsonConfiguration.Exists(ConfigFileName)) -{ - var defaultInstance = new LiveReloadConfig() - { - Server = "http://localhost:8080/", - Path = ".", - Extensions = new []{ ".cshtml", ".css", ".js", ".html" } - }; - - JsonConfiguration.Put(ConfigFileName, defaultInstance); - - Console.WriteLine("Missing config.json. One has been created for your convenience."); - Console.WriteLine("No thank you necessary..."); - Environment.Exit(0); -} - -Console.WriteLine("Loading config.json"); - -var config = JsonConfiguration.Get(ConfigFileName); - -Console.WriteLine("About to connect to SignalR running at {0}...", config.Server); -Console.WriteLine("About to start watching {0} for changes to {1}", config.Path, string.Join(",", config.Extensions)); - -var broadcaster = new LiveReloadBroadcaster(config.Server, config.Path, config.Extensions); -broadcaster.Start(); - -Console.WriteLine("Press any key to continue..."); -Console.ReadKey(true); - -broadcaster.Stop(); diff --git a/samples/signalr-livereload/usings.csx b/samples/signalr-livereload/usings.csx deleted file mode 100644 index 4b76b83b..00000000 --- a/samples/signalr-livereload/usings.csx +++ /dev/null @@ -1,9 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNet.SignalR; -using Microsoft.AspNet.SignalR.Client.Hubs; -using Newtonsoft.Json; diff --git a/samples/webapihost/packages.config b/samples/webapihost/packages.config deleted file mode 100644 index 24e17745..00000000 --- a/samples/webapihost/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/samples/webapihost/server.csx b/samples/webapihost/server.csx deleted file mode 100644 index e694a72f..00000000 --- a/samples/webapihost/server.csx +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.IO; -using System.Web.Http; -using System.Web.Http.SelfHost; -using System.Web.Http.Dispatcher; - -public class TestController : System.Web.Http.ApiController { - - public string Get() { - return "Hello world!"; - } -} - -public class ControllerResolver : DefaultHttpControllerTypeResolver { - - public override ICollection GetControllerTypes(IAssembliesResolver assembliesResolver) { - - var types = Assembly.GetExecutingAssembly().GetTypes(); - return types.Where(x => typeof(System.Web.Http.Controllers.IHttpController).IsAssignableFrom(x)).ToList(); - } - -} - -var address = "http://localhost:8080"; -var conf = new HttpSelfHostConfiguration(new Uri(address)); -conf.Services.Replace(typeof(IHttpControllerTypeResolver), new ControllerResolver()); - -conf.Routes.MapHttpRoute(name: "DefaultApi", - routeTemplate: "api/{controller}/{id}", - defaults: new { id = RouteParameter.Optional } -); - -Console.WriteLine(Assembly.GetAssembly(typeof(TestController)).FullName); -Console.WriteLine(Assembly.GetAssembly(typeof(TestController)).IsDynamic); - -var server = new HttpSelfHostServer(conf); -server.OpenAsync().Wait(); -Console.WriteLine("Listening..."); -Console.ReadKey(); \ No newline at end of file diff --git a/samples/wpf/CalculatorView.xaml b/samples/wpf/CalculatorView.xaml deleted file mode 100644 index 57d7d172..00000000 --- a/samples/wpf/CalculatorView.xaml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/wpf/app.csx b/samples/wpf/app.csx deleted file mode 100644 index 51a4e86c..00000000 --- a/samples/wpf/app.csx +++ /dev/null @@ -1,33 +0,0 @@ -#r "PresentationCore" -#r "PresentationFramework" -#r "WindowsBase" -#r "System.Xaml" -#r "System.Xml" - -#load utilities.csx -#load mvvm.csx - -#load viewmodels.csx -#load views.csx - -using System; -using System.Windows; -using System.Threading; - -public class App : Application -{ - protected override void OnStartup(StartupEventArgs e) - { - var viewModel = new CalculatorViewModel(); - - var window = new CalculatorView - { - DataContext = viewModel, - SizeToContent = SizeToContent.WidthAndHeight - }; - - window.Show(); - } -} - -Utilities.RunInSTAThread(() => new App().Run()); \ No newline at end of file diff --git a/samples/wpf/mvvm.csx b/samples/wpf/mvvm.csx deleted file mode 100644 index 1f732677..00000000 --- a/samples/wpf/mvvm.csx +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Windows.Input; - -public class ViewModelBase : INotifyPropertyChanged -{ - public event PropertyChangedEventHandler PropertyChanged; - - protected virtual void NotifyPropertyChanged(string propertyName) - { - var handler = PropertyChanged; - if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); - } -} - -public class RelayCommand : ICommand -{ - private readonly Action _execute; - - private readonly Func _canExecute; - - public RelayCommand(Action execute) : this(execute, null) { } - - public RelayCommand(Action execute, Func canExecute) - { - if (execute == null) throw new ArgumentNullException("execute"); - - _execute = execute; - _canExecute = canExecute; - } - - [DebuggerStepThrough] - public bool CanExecute(object parameter) - { - return _canExecute == null || _canExecute(parameter); - } - - public event EventHandler CanExecuteChanged - { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - public void Execute(object parameter) - { - _execute(parameter); - } -} \ No newline at end of file diff --git a/samples/wpf/utilities.csx b/samples/wpf/utilities.csx deleted file mode 100644 index f3f24725..00000000 --- a/samples/wpf/utilities.csx +++ /dev/null @@ -1,24 +0,0 @@ -using System.IO; -using System.Threading; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Markup; - -public static class Utilities -{ - public static void LoadXaml(ContentControl contentControl, string xamlFile) - { - using (var fileStream = File.OpenRead(xamlFile)) - { - contentControl.Content = XamlReader.Load(fileStream) as DependencyObject; - } - } - - public static void RunInSTAThread(ThreadStart threadStart) - { - var thread = new Thread(threadStart); - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - thread.Join(); - } -} \ No newline at end of file diff --git a/samples/wpf/viewmodels.csx b/samples/wpf/viewmodels.csx deleted file mode 100644 index 790be2ba..00000000 --- a/samples/wpf/viewmodels.csx +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Windows.Input; - -public class CalculatorViewModel : ViewModelBase -{ - private string _display; - - public CalculatorViewModel() - { - Display = "0"; - - NumberCommand = new RelayCommand(param => AddNumber(Convert.ToInt32(param)), param => CanAddNumber); - - AddCommand = CreateOperatorCommand('+'); - SubtractCommand = CreateOperatorCommand('-'); - MultiplyCommand = CreateOperatorCommand('*'); - DivideCommand = CreateOperatorCommand('/'); - - CalculateCommand = new RelayCommand(param => Calculate(), param => CanCalculate); - ClearCommand = new RelayCommand(param => Clear(), param => true); - } - - public string Display - { - get { return _display; } - set - { - _display = value; - NotifyPropertyChanged("Display"); - CommandManager.InvalidateRequerySuggested(); - } - } - - public RelayCommand NumberCommand { get; private set; } - - public RelayCommand AddCommand { get; private set; } - - public RelayCommand SubtractCommand { get; private set; } - - public RelayCommand MultiplyCommand { get; private set; } - - public RelayCommand DivideCommand { get; private set; } - - public RelayCommand CalculateCommand { get; private set; } - - public RelayCommand ClearCommand { get; private set; } - - private int? Operand1 { get; set; } - - private char? Operator { get; set; } - - private int? Operand2 { get; set; } - - private int? Result { get; set; } - - private bool CanApplyOperator - { - get { return Operand1.HasValue && !Operator.HasValue; } - } - - private void ApplyOperator(char @operator) - { - Operator = @operator; - Display = string.Format("{0} {1} ", Display, Operator); - } - - private bool CanAddNumber - { - get { return !Result.HasValue; } - } - - private void AddNumber(int number) - { - if (Operator.HasValue) - { - Operand2 = !Operand2.HasValue ? number : (Operand2 * 10) + number; - Display += number; - return; - } - - Operand1 = !Operand1.HasValue ? number : (Operand1 * 10) + number; - Display += number; - } - - private bool CanCalculate - { - get { return Operand1.HasValue && Operator.HasValue && Operand2.HasValue && !Result.HasValue; } - } - - private void Calculate() - { - switch (Operator) - { - case '+': - Result = Operand1 + Operand2; - break; - case '-': - Result = Operand1 - Operand2; - break; - case '*': - Result = Operand1 * Operand2; - break; - case '/': - Result = Operand1 / Operand2; - break; - } - - Display = Result.ToString(); - } - - private void Clear() - { - Operand1 = null; - Operator = null; - Operand2 = null; - Result = null; - Display = "0"; - } - - private RelayCommand CreateOperatorCommand(char @operator) - { - return new RelayCommand(param => ApplyOperator(@operator), param => CanApplyOperator); - } -} \ No newline at end of file diff --git a/samples/wpf/views.csx b/samples/wpf/views.csx deleted file mode 100644 index 159b24db..00000000 --- a/samples/wpf/views.csx +++ /dev/null @@ -1,7 +0,0 @@ -public class CalculatorView : Window -{ - public CalculatorView() - { - Utilities.LoadXaml(this, "CalculatorView.xaml"); - } -} \ No newline at end of file From 4d1b065ac954deb752bb46aca36b75dd1786c47f Mon Sep 17 00:00:00 2001 From: Filip W Date: Wed, 13 Mar 2013 22:06:55 -0400 Subject: [PATCH 0108/1224] added PowerArgs for cmd argument parsing --- src/ScriptCs/Program.cs | 40 +++++++++--------------------------- src/ScriptCs/ScriptCs.csproj | 6 ++++++ src/ScriptCs/ScriptCsArgs.cs | 20 ++++++++++++++++++ src/ScriptCs/packages.config | 4 ++++ 4 files changed, 40 insertions(+), 30 deletions(-) create mode 100644 src/ScriptCs/ScriptCsArgs.cs create mode 100644 src/ScriptCs/packages.config diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 696c7db3..61c51b6e 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,43 +1,28 @@ using System; using System.ComponentModel.Composition.Hosting; using System.Linq; +using PowerArgs; using ScriptCs.Engine.Roslyn; -using ScriptCs.Exceptions; +using System.ComponentModel.Composition.Registration; +using ScriptCs.Contracts; +using ScriptCs.Package; namespace ScriptCs { - using System.ComponentModel.Composition.Registration; - - using ScriptCs.Contracts; - using ScriptCs.Package; - internal class Program { private static void Main(string[] args) { - if (args.Length == 0) + var commandArgs = Args.Parse(args); + + if (!commandArgs.IsValid()) { - WriteUsageMessage(); + Console.WriteLine(ArgUsage.GetUsage()); return; } - var script = args[0]; - bool debug = false; - - if (args.Length == 2) - { - var secondParam = args[1]; - if (secondParam.Equals("-debug")) - { - debug = true; - } - else - { - Console.WriteLine("Unrecognized parameter {0}.", secondParam); - WriteUsageMessage(); - return; - } - } + var script = commandArgs.ScriptName; + var debug = commandArgs.DebugFlag; var container = ConfigureMef(debug); var fileSystem = container.GetExportedValue(); @@ -62,11 +47,6 @@ private static void Main(string[] args) } } - private static void WriteUsageMessage() - { - Console.WriteLine("Usage:\r\n\r\nscriptcs csxFile [-debug]\r\n"); - } - private static CompositionContainer ConfigureMef(bool debug) { var conventions = SetupMefConventions(debug); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index df54235d..522477a9 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -6,11 +6,15 @@ Exe ScriptCs scriptcs + ..\..\ ..\..\common\Icon.ico + + ..\..\packages\PowerArgs.1.2.0.1\lib\net40\PowerArgs.dll + @@ -31,9 +35,11 @@ + + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs new file mode 100644 index 00000000..910d12a1 --- /dev/null +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -0,0 +1,20 @@ +using PowerArgs; + +namespace ScriptCs +{ + public class ScriptCsArgs + { + [ArgDescription("Script file name")] + [ArgPosition(0)] + public string ScriptName { get; set; } + + [ArgDescription("Flag which switches on debug mode")] + [ArgShortcut("debug")] + public bool DebugFlag { get; set; } + + public bool IsValid() + { + return !string.IsNullOrWhiteSpace(ScriptName); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config new file mode 100644 index 00000000..0c45fa6c --- /dev/null +++ b/src/ScriptCs/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 1559d728d49331708c40fae1e9a881781167d346 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Wed, 13 Mar 2013 23:45:17 -0300 Subject: [PATCH 0109/1224] # Updated text for DEBUGGING.md. Still need to add images --- docs/DEBUGGING.md | 135 +++++++++------------------------------------- 1 file changed, 25 insertions(+), 110 deletions(-) diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index c82ec184..3c7ea716 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -1,112 +1,27 @@ scriptcs Debugging overview =========================== -This document explains the steps required to debug .csx files with scriptcs. This document also goes over the limitations of the current debugging approach and the reasons for those limitations. - -What you will be able to do ---------------------------- -* Use [mdbg](http://msdn.microsoft.com/en-us/library/ms229861.aspx) to debug .csx scripts. -* Place breakpoints in your code using `Debugger.Break();`. No need to add the `using System.Diagnostics;` as it is automatically added when debugging. We are considering the usage of `#debug` instead of `Debugger.Break();` as it is less verbose. The downside is that you would lose direct portability to a VS project (feedback?). -* Compile your .csxs to .dlls. - -What you won't be able to do ------------------------------ -* Use VS to debug. -* Use mdbg to get the current line of code. - -The aforementioned limitations are due to the fact that: -1. The compiled code is not a 1 to 1 mapping of the .csx files. -2. The generated .pdb files do not point to the source file (due to 1.) - -Debugging with scriptcs ------------------------ -The following example shows how you can debug the [WebApiHost sample](https://github.com/scriptcs/scriptcs/tree/dev/samples/webapihost) using scriptcs. This procedure assumes that you have the .csx, packages.config and Packages folder already setup. -Additionally, you should have mdbg.exe already installed with support for .NET 4 configured in your PATH (if you have VS installed it should be under **C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools** and **C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools\x64**). This sample uses the x64 version, but you might need to use the other one (this is explained below). - -1. Open server.csx and add a debugger break to the **TestController**'s **Get** method: - - ``` - public string Get() { - Debugger.Break(); - - return "Hello World"; - } - ``` - -2. Open your two instances of your favorite command line tool (let's call them *console1* and *console2*) and cd to the directory where server.csx is located. - -3. In *console1* enter `scriptcs.exe server.csx -debug`. The output should look like the following one (notice the scriptcs automatically halts before starting to run your scripts' code): - - ``` - PS C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug> .\scriptcs.exe server.csx -debug - Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.AspNet.Web - Api.Client.4.0.20710.0\lib\net40\System.Net.Http.Formatting.dll - Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.AspNet.Web - Api.Core.4.0.20710.0\lib\net40\System.Web.Http.dll - Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.AspNet.Web - Api.SelfHost.4.0.20918.0\lib\net40\System.Web.Http.SelfHost.dll - Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.Net.Http.2 - .0.20710.0\lib\net40\System.Net.Http.dll - Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Microsoft.Net.Http.2 - .0.20710.0\lib\net40\System.Net.Http.WebRequest.dll - Found assembly reference: C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\packages\Newtonsoft.Json.4.5. - 11\lib\net40\Newtonsoft.Json.dll - Attach to process 7148 and press ENTER. Then use the 'go' command in the debugger. - ``` - -4. In *console2* execute `mdbg.exe` and run `processenum`. The output should look like this (the important entry is 1988, the scriptcs.exe one, which should match the number displayed by scriptcs. If it is not there, use the other version of mdbg.exe): - - ``` - PS C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug> mdbg.exe - MDbg (Managed debugger) v4.0.30319.1 (RTMRel.030319-0100) started. - Copyright (C) Microsoft Corporation. All rights reserved. - - For information about commands type "help"; - to exit program type "quit". - - mdbg> processenum - Active processes on current machine: - (PID: 2156) C:\Windows\Explorer.EXE - v4.0.30319 - (PID: 4056) C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe - v2.0.50727 - (PID: 6548) C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe - v2.0.50727 - (PID: 7148) C:\Users\Damian\Documents\GitHub\scriptcs\src\Scriptcs\bin\debug\scriptcs.exe - v4.0.30319 - ``` - -5. Attach to 7148 by running `attach 7148` in *console2*. -6. In *console1* press ENTER to continue start running your scripts. -7. In *console2* run `go` (it's like F5 in VS). In this case, mdbg.exe will not return the prompt as it is waiting for the breakpoint to be hit, but `Listening...` will be displayed in *console1* (among other things). -8. Open your web-browser of choice and browse http://localhost:8080/api/Test. -9. Go to *console2*. mdbg.exe will have stopped at the breakpoint displaying the following: - - ``` - STOP UserBreak - located at line 17 in - [p#:0, t#:8] mdbg> - ``` - -When using only one file, the correct line number is displayed (or almost). This could get complicated if you have multiple files and various breakpoints. That would be another of the uses for `#debug`, which could be replaced by the following so scriptcs could give you an idea of where you are standing: - -``` -Console.WriteLine("{0}:{1}", originalFileName, originalLineNumber); -Debugger.Break(); -``` - -Now you can run any mdbg.exe command. For example, running `print this` outputs the following: - -``` -[p#:0, t#:8] mdbg> print this -this=Submission#0+TestController - _disposed=False - _request=System.Net.Http.HttpRequestMessage - _modelState=System.Web.Http.ModelBinding.ModelStateDictionary - _configuration=System.Web.Http.SelfHost.HttpSelfHostConfiguration - _controllerContext=System.Web.Http.Controllers.HttpControllerContext - _urlHelper= -``` - -Inside the bin folder you will find server.pdb and server.dll. - -If you have any feedback feel free to open an issue. \ No newline at end of file +This document explains by example the steps required to use Visual Studio to debug .csx files that are executed with scriptcs. Hopefully you won't need to debug very often, but if you are in need be sure to follow this example. + +Prerequisites +-------------- +1. The following example shows how you can debug the [WebApiHost sample](https://github.com/scriptcs/scriptcs-samples/tree/master/webapihost). This procedure assumes that you have the .csx, packages.config and Packages folder already setup. +2. You must have the [Roslyn CTP](http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx) installed to get VS to recognize .csx files. + +Steps +----- +1. Open Visual Studio. +2. Open the **Open Project** dialog by navigating to File -> Open -> Project/Solution. + [openProject] + The resulting solution explorer should look like this: + [solutionExplorer] +3. Right-click the scriptcs solution item and click **Properties**. +4. Provide values for the following fields: + * Arguments: `server.csx -debug` + * Working directory: the source folder of the app you want to debug, in this the directory where server.csx is located. +5. Close the **Properties** window and save the solution. +6. Add server.csx to the solution by right-clicking the solution and selecting **Add Existing Item**. +7. Set a breakpoint in the `return "Hello World";` line of the **TestController**. +8. Press F5. +9. Open any browser and navigate to localhost:8080/api/test. + +That's it, the breakpoint will be hit. You have all the goodness of VS, such as the Immediate Window, Add Watch to help you debugging. \ No newline at end of file From abac49da8481aabb122da7af6dea875df86f960a Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Wed, 13 Mar 2013 23:48:23 -0300 Subject: [PATCH 0110/1224] # ADded images/DEBUGGING --- docs/images/DEBUGGING/breakpoint.png | Bin 0 -> 32119 bytes docs/images/DEBUGGING/emptyProject.png | Bin 0 -> 52719 bytes docs/images/DEBUGGING/hitbreakpoint.png | Bin 0 -> 39575 bytes docs/images/DEBUGGING/openscriptcs.png | Bin 0 -> 61954 bytes docs/images/DEBUGGING/rightClick.png | Bin 0 -> 17135 bytes docs/images/DEBUGGING/solutionExplorer.png | Bin 0 -> 6508 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/DEBUGGING/breakpoint.png create mode 100644 docs/images/DEBUGGING/emptyProject.png create mode 100644 docs/images/DEBUGGING/hitbreakpoint.png create mode 100644 docs/images/DEBUGGING/openscriptcs.png create mode 100644 docs/images/DEBUGGING/rightClick.png create mode 100644 docs/images/DEBUGGING/solutionExplorer.png diff --git a/docs/images/DEBUGGING/breakpoint.png b/docs/images/DEBUGGING/breakpoint.png new file mode 100644 index 0000000000000000000000000000000000000000..0d19ab355f7f7a8eaaf6ff27e765a5fef641094d GIT binary patch literal 32119 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

<=;$$X~!Gj%F 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 P_)p=!icGnbN#Oqj2TCJl literal 0 HcmV?d00001 diff --git a/docs/images/DEBUGGING/hitbreakpoint.png b/docs/images/DEBUGGING/hitbreakpoint.png new file mode 100644 index 0000000000000000000000000000000000000000..7e32653c33c0de3926c7778d2d21a8ffc3bd1d7e GIT binary patch literal 39575 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 R=>P)|c)I$ztaD0e0syGX1DgN< literal 0 HcmV?d00001 diff --git a/docs/images/DEBUGGING/openscriptcs.png b/docs/images/DEBUGGING/openscriptcs.png new file mode 100644 index 0000000000000000000000000000000000000000..484ca7ab4172525ad5d63071e52651990f5d4c9e GIT binary patch literal 61954 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 Iv#8+z0*uMkWB>pF literal 0 HcmV?d00001 diff --git a/docs/images/DEBUGGING/rightClick.png b/docs/images/DEBUGGING/rightClick.png new file mode 100644 index 0000000000000000000000000000000000000000..6f589c2dbf2fa777c8b424220a46c01d8c815f5c GIT binary patch literal 17135 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 literal 0 HcmV?d00001 diff --git a/docs/images/DEBUGGING/solutionExplorer.png b/docs/images/DEBUGGING/solutionExplorer.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9500b9292a08bd7ec239313484d3b6d613e7dc GIT binary patch literal 6508 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 literal 0 HcmV?d00001 From a529330f4fb6222c718b797fbf23884e4e2fa83d Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Wed, 13 Mar 2013 23:55:16 -0300 Subject: [PATCH 0111/1224] Update DEBUGGING.md to include images --- docs/DEBUGGING.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index 3c7ea716..aedb2aef 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -11,17 +11,22 @@ Steps ----- 1. Open Visual Studio. 2. Open the **Open Project** dialog by navigating to File -> Open -> Project/Solution. - [openProject] + ![open project](images/DEBUGGING/openscriptcs.png) + The resulting solution explorer should look like this: - [solutionExplorer] + + ![solution explorer](images/DEBUGGING/solutionExplorer.png) 3. Right-click the scriptcs solution item and click **Properties**. 4. Provide values for the following fields: * Arguments: `server.csx -debug` * Working directory: the source folder of the app you want to debug, in this the directory where server.csx is located. + ![properties](images/DEBUGGING/rightClick.png) 5. Close the **Properties** window and save the solution. 6. Add server.csx to the solution by right-clicking the solution and selecting **Add Existing Item**. 7. Set a breakpoint in the `return "Hello World";` line of the **TestController**. + ![set breakpoint](images/DEBUGGING/breakpoint.png) 8. Press F5. 9. Open any browser and navigate to localhost:8080/api/test. -That's it, the breakpoint will be hit. You have all the goodness of VS, such as the Immediate Window, Add Watch to help you debugging. \ No newline at end of file +That's it, the breakpoint will be hit. You have all the goodness of VS, such as the Immediate Window, Add Watch to help you debugging. +![hit breakpoint](images/DEBUGGING/hitbreakpoint.png) From 91354ce13a30583540b0edfb71bade70ac752171 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Wed, 13 Mar 2013 23:55:36 -0300 Subject: [PATCH 0112/1224] Removed emptyProject.png --- docs/images/DEBUGGING/emptyProject.png | Bin 52719 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/images/DEBUGGING/emptyProject.png diff --git a/docs/images/DEBUGGING/emptyProject.png b/docs/images/DEBUGGING/emptyProject.png deleted file mode 100644 index fdabe01e2760f1ec86f6a25b45a979b95b1a1fa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52719 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

<=;$$X~!Gj%F zg!3VF2k=vkyGrh260(k%{=C8hyrP#er;UBhmGK&uu!;yCB?rKVXEi>Ef2b)4bHedM zKw25~@p8)9J@dXH%quvJbX+^JN7dTHE8_6hX>o)D7_oXp#lIdny9dVuyv3u`qe_B( znDJz5Y}VTXl^Zh`4oE)6G!eZIUP2zNbyyO3T)%x|&;1MhmVk4n`N=x_i*Qfs#v=ip%b+6ytB@ z^9?yNUNrDExaUi^mp40R795u?bYv{ism1fn)~S0-1yB70YN?R*7uJBvl?IjFW?&t+ z_VAs+W^@Bi9(<<~M6dQ*XpPJw^?0ylRu)}86Nm6G1xf<1YTG|;pTov7uq0AzcUR9y zsmiI5+{CJ%Oj{D%eZAwclZ_1)f33mcFSyNQ%BA}w7H{TZGTsGQG4JVfJp7z*u~w^! z?%!W^6p7(Tyj&(F;%=z^UV zo_Gi|iKfE3J>?7@){K5gon{x~Pqg$>n8MDo?b>wkFPXUSB=~BWVVcjF3I7*%g+r*( zYv~7lHaGyxJlW+Q=eSM>C%z%tU};iA zi}pR+l<@k#QgTts3sS>p<3hFyRg_;EF(Ywz^GRT7J6DxL?H+FYXcvn4@;}pY=_^w2 zWS~J~Y-}6HRBqqhy=^};>P&ToR@e79 z^|SFRpAjFDaWRiIgVti;WJXtc(AJ}l?CF3@?L@?DT2-v0o!&DX9Uuu50{vuK5rnX~ ztoVEJu?%dnaYqB)#8J;~pD-{UIBb|9RBFc^BvX!VttPN6pI7N#$-Dj0SmlVRX2w^! zdkB$3S8yWDxG0$!D5o~YN@1X9K~y5;{2Wn>L=OjiL7)VNtV-JVE7!sjR*j4{_; z)3QgjsFu}7(}_lRc8hJxjdZ#X@*004y{9B`wAvB`!Wmd#7UVGRl5lP$UD8#A>i+U; zsfeuVn5~>Vy3_3#V52vpqIYmIkYk8pS#Vm2m?>7DCL=`qhBxS7eo}Q;yfW)7k*XT} zfPY{eQqN}E10Iq$kBY$!j?x;kfqU^9g2n1CxY^4xbIFxRIffoIdrloM;$lq>zba!P4_!AT@^_hPkgd{Q#@Ua#PgDh zERt*mTe`hpyb{|^G@sEgu|KnZ3d!V5Q~>{Sr6ZZP?d0go)8mQm4^JlXAC6nxN&G8T zXM$`bDP6fyBO*o^x~L75*~53!GJO$9Cqh#6;*{%R&9(oZq4o=I?3pADjIX8h<4|y^ zfQu&YwbXU{)@ux$?*5XoH&|4$7Wru)YK<6#?wrFh@1iS0Q*1D^xTE%HI#CW6QdR7G z_6I4gfPX5_sldFro5O?r29K?ZPW@N7#Uby=9JnIv#&38aIJaJ8_N zdzYV{!;UOPEL~!_)!=p8+0)nVm!hJSWYE5wG9>gdtYk!OC@gE!c};(PjkPBC=k3?&7OsH`%5#Nc%N z)G5aL+MJwhTofmx3qwSdVNI*LFnDW176=uQ21e$3?l2ko0h*FR+(mBzQ^$mB3f*VV zNV|-Y;IMJ4R8hskbOx6RUVa_s`{a7y;uZ0;;ONP7R#rf95B?|)MnBwEEru2|{r=cc zUXEgOdlrQ>omTH>SxFhV`Ljnq{LM?VH_K{3FdE&#ZSPWgUM8szMjpTvU8H`V>|UMt zac(X5hjhiAoaAf~q=4=m1}?3lny~o2#zZdLkJVDjozQn<0WVfpT~?F z7|?&3e%vBWCmn$Fym_;N=F5X-as1JN%M7Nh?nUbSWF*>;a!;+7h_1ZVIdRbVP%lon z=+O4^h6X@p+A!Gs)4#3_$2(prXV zpA=(C7oa`6xq`p^22(k%BPGdZQ)N9o7hPj98XknuJ;@CdwY6{X5w{W!`(lDmX7M;Y zfHsp5lk%Yuj)HZHxLuE~bu5@Mo4S`==>j37zG3 zo?m{9y`f0Ue9?zWNNq? za2kCX?EKiHvP^AnHh7Z>@;JLTQsnkj^b@zka*i6`Ex)ffvxl?3)3k_!`!wHMSc~1D z?PUCV3ayBF$?D3w@$rpM$?`_VYGw@ZP7Y07g$Am)6)Q_-!-J67G6riC8CRRl%9l6B zSRWdK(I?at7bpbA*jbpDxaXo!cOJ2oUkZ9Qk)W$t8>!V=m%&XTY{K1k zTT@N;h=sF5^Qn^LjD*e4r4J+qoofkG{2bji-9($-^;AM%>TCFiMo^eIU})c(Vt4~KnO$*6*hRGs>a#IXKaS6>r4dU zLe3#_M#-J2-h9gojj)A+x_hNkjL8bfJDDR*`1KSaASaXdu_J5F8xASgbC=z)kdC_7;ZFb=mC_X2@|)My2jm zEde)D+ufoT7f+I#pHr}ofnI`#UVIT1Bd!%81)=5O5php)vVBJY8i-S}o$szN$F^L_W!d;|Lr2N z4`}XC!5W383=!|O>(EyA{B>POi8)TzTmj~?7Bn%hPS14k#z39zM6v%Kh?)%>4Ayb# z=AvuRs8{Fl-w?qzo~V1oD{3~(95ah!#M;7j{ViW!*Z1v6`?{^@{&pO{SPkb&pFqLw zO!D<9E+Lazd~T$m)uXtl+}OJxK_DzYAXWUw;dbC6D}BKVO0qYGcr?Xg?lWwFf z`Bjr)?8` zu^BCo(57_d`NS$3&;Doay=zG)bfgHW#e(RV`_(mSP+Opgqt-^iM#Bp`uxeEXZ!-vm(~sQ?#p$~@An0yS#~XPK;vdhz$*CB3nf**zp6n@Tk1P@YMEjjr9Bgg544-H4dTtq5gi%_pOBExU)^~o~_3-oO>s%n&PMo z_Q70~?wAzXhl*UtWJ_I0@?-HU$!?}+n3E$u*p!a+Rgc)~UODB%5 zqf7iZgumrA<|4AEjBz3EJLsUWQEII#(_gd%N|XqQVp&Qi}pG*TzVj5(MItkx}h1D{}j0O$ExsV#8v-1-*&fqP0)zxb*J0;^x&-bd*b)b{!b=u!2n z(CmKV!#(NA_6>k8sQY$<2l4Y3O6b=OP4VIBQHuA*zQUPiSYRLwt9bhVo@?Xz1R{~d zDR<$FEmtZ_axT8;>48ONO&# zZxEX8+n1bEw=^k=A$yjbC4a5!099z8O*KvtJw2u|+o{PXbDfownYnP-MH;@Qs~Li;i8oym6LjXfSz_zRBfP z)9o^p>*!YL!f z6W2$C2{w75MWcMTlkArV+v^`%;pj6o5NuFTn`js7T z8hF(>+3fY|RbYCZUZkZ__)qz<>HDI?h%r-;C_sI%hIbsiB4ST}^Or0%X{(v%JedOZY@WVMo?M1*#D zSchs#q(=AP(roMB$d0ri71lL%9TVst@AIW%KpJVL@b;9J z(8p4B^7x~!z323sSFAMfeV6-N4I<0`#jEDhydnY7VgL5<81X-cb!bOj^%VNXds^CsdHk!$PYdf9fQH$ zPtdh!NPU4CX2#&j1`qq*DPLo=n?^uP^&~~v#%JzsxP;f!B$H>li|Ju;qhC+Q!9sgL zRUZ#QmOA9(0X$O|b1l|{UT3x7KDEe98G{o+zn`69TCS@|nQ2%I8;fSZXoM<|x6vcD5eJhKC2K9^h`m0L>0WB9JT4?tc z7mE$r7E82d8%0{Y5pvyQJ~K76Q;X(^KqB`nq-Ahn8*G(RPG_(Fj^Ij|~ zWp0oL%)E5<-S6=+p_RkVMOV>D1dBJJW8s!7%mcTOBx+BF$%r5X3K;!Zz3Dy(5c;k>TlVt990!jL z@NGSoN-kCl;*vVsM+w^)2i>u@JZ`p=KUv|=P!f_gjR6t@#T zEu&-Hr^R@i)a(9`PT^j`=i`DN`z0^?Lw15B~vY*gLz3cD>g4X5bV^ zW285(fO?kUB8LfY7Rsuou8Jg8n?tjlhc73~EMlN~sftp_NzjQ=9aF#>f%udN{uU%5 z&MQg4l}u;vVK3js1U$=#578t+eWGHyKmq#(?xRzrAoa>Ud_zdAFX8CBtY~qq5S*_q zQx^QhffE0fE5G`fo)@jNpnZp#N#A0w$CyI*o-PC;ANi1*fFh+_03w0=0`49JC=Xcf zfO6J^>$(=YRWT3}Ru_T%+~%PCIyJqJ^&daCSh|3o$E|6TO^EH)J|M7(xp>Fx^LkqJ z0NMKo?=CAPYJk$TDI&-d2-vajvyiy~z3tzSym6XGRqlf`NP(2l7o7M+jSn${$qQ9M zcYMC`eL6B3(+F|8Jy7%0-uL$7kDEUj=3ol1?xqJuEDQDFh8Z8^cH3=t_$SHp60>(PGM5?G%p)Mbv9h506F8!tPV!`mHEjxPA z7%`Y0rqVj$2^2>WcK`(1;f5iG=NQ)c;L^lFGNt`U7H$ArLb+LZDa->JQh2;lvSR=UU9!4Y>G(q`4W{xA>6x zs5?pTH7O8>eXCWUve>)_r*K_U)TtpMG3}?RwSx0gmI$Lm_=3^;h>OOgI1sY1KBvuC zN*n_kU}hbVcmj)YLl_K{CAhd)KzQmB!tr9FD-m2t)9P~3k|>l!q13{`p>TYh=&K3y z6?8_)sRpwT@^bM)aijO}}PH46%9RTtw_IsgFkTZ-1+M*tCcmjTw)Eo>GrM z{Oifs`1Y^};${`LjVU+)@>%)n=OGMm212Bp&Kgt1kaQo+EqcxB7Ky!8)Bn}1{e9E@ zV{&k%2s7x1@F2U#uZI#HXW(xWnHEA?+*$Jf@AH38|DW6AU&6Yp;-tlECftb-c-}=k za-G=$FkH@;^Uo5{n?p9&dbMx8=)a$jygWWRdA+%Hh%-3paPofyY;C6WI04!lJ-`tE zVFf{*rDNCZP7~;~2F_YvORQ(m(YIB=x(PpZ>M8K1`#-dLo6cWvfHHORV-%^%CPnQa z#?`<;r(jgvHxy8~8GxOwy1BIu?;R4E3B9j8jvW6#5EXTaL?ssA7T6Y8o+kFDz_s1H zM)KSeLWBS@iUgD~i`Pg)AQJSn0*5@iLZBJuXh#HP~^;2wpxZ050@{mpQMms7d|cBTjJkjJBtf5_ ziT^IwIe<4CE8~bn%=rer%JZ>&*iwBxFEzz1OLo-ooWrbW@t-pk16fb@Q#U_?2!SGX zE{1hwxWq%MwleG4rz4;VuMt1i1R!FuAzJAWStTWXS`2>9c(arc+V=L7KP9wwrQq&a z(0i!y+N6k>>}EmM$dIyvsuNC9LD%$@| zN>=nwTeR7OaaTQ^6iLw$e025aEeaA}|_xl_C(Q?M=! ziFkO$$h`E;&7fQmVT3JfP(uaD?*y>X{Qf&c&t2G}`yJP!w_T&Sv5qEfAi5?*P}R$% zMjJjcphjS^HVcc{@ubMG(_*<|qTi!q1cYx0VPrzwG`80conTdTIu386e}1EXp^WaJ zxq({J?FTYkCoV<}TOpG$ScefNu%dz1g&plRtddi%Wy+$9mQJ*8DOGy5rXXjbMR=QA zSnG-~Fe;$+1A^e^k;~#GewgVWSs7{yN=jDR7z}r(gT0@h0R<0r*Aro!9 z&5rW`_M+KQK{>6JXv*rwYgQa;JO2RRGjZ9ktEjBxKIJ}LJKAp?zYxlM*0WcuK%w8HxI&Nhs#5E$Lr5El9DZAQdxZhc!i|-Bo4q|CX3OOBor<(Vcu})L{702Uf91tBZSBL5nFx*qbuf z!qk&zRE3$>5ORnMh~=NI62`x(+Yti-vs(s#V&cE~ubf2=@F7Th7zv0&(JkBcDjbXWqiRsB~9q@Ub#c?cs ze!uS!uJ4rNQ~xAg@q+pQ@41sN?9W_YoLX?duub<~W#N1-gb-grS7%Xo= zu8jY$08A-IV!05(Vz1y zz|Kbu9|b=?49Xn5u$G+Ir-M0f-LP)7C1H20sV$Mg^n#rPT#s^8;ZrU`_w@npidvF- zn|AFo5~4o8Ww(hc*aYQ#)`}}17yNxWbyTv06*%XwEMIailXy+(&M>^9v5ZyfK)f9_ z30QYdElT(cQuo`4^GVt0l?Gm|fhTy2=QEm3a)14*G`J+tM{ByX}b- z+M-1wnFd~m=djuu9V8VUeRQsW-xS0vzi~~jhq7*n-An(&Y`^-vQ$5?D-udYp=Ka8;B2c3t=p)Tc z0O^Y(aSau(S8bL93fq~-%+J=%MBJk}iD=r^(L(ncTMWL@7*2We- zs6P()FOt|15m-`BI_~~6%O$IuL7k+j^I*L z4Ohl$iE6_iS)V6qE=h=Ss5I8w^x8MtdwIZxfd8C_ND=$|E9&DWMK~Y)d7AIe>$)DJ zum!^}@4d`o(@P~nAP4-Eakt@!h;G%DvFz)L6PvHfan6Q{U;Qh4WS{Ot(2s}Cc-^Z zh=Xu%AhlGh$H&N+B6TNv$N{fJesstdi5+{M2e*{p09p03sQr-8zRo1U-y7~7FWJBh z?tqNJzI}6m`l(4#&p&Q=8UAEw+P>PoA|^CV_5*KR_V$|wb`8ptYWO#srmHu6gTqpN zQ1(F6OHLW%k#-f)f!3>ObrlD=rd=R=iJ4CId0g(!>beL8-X8ldgLD z8z$AR{0*hn<=_&chN+Y= zb%5qMpK1hU{j||@Cse8|62CT}6$KDlNNWgA@o&Nn`Et?Od&>EiMVn|*t@NmRGG5_+ zJ9VuG4H13Xvr)YLQU2qUG^peGyV;WSsL=@zuKR2dxHtoQ4E?5u1{uMZI1th8XfmcT z9FM4>wiRi2MO`Je?@E_zB`ivow} z66jvfOreS;1rWK2BLz*!{!9TFv#==s#y$Lle^}gqWAdleb47wCMP%S74weUmQ~a7X zKu#`kj`ZQ5R``$s+qMvOM*{-qKlz?37%af;A8x)jWOBIC3m9eNbheO!{QUg?k;vGT z{wZ3jz%j~>ztn*QQuNPnA@fx%_h-On`Gm%0ysfb<6`DJdR8=)PRJImqn>Y4r1}qrpKy=eX-l ziKdayX|GI%9yVn<__J)Yuy86i)?f76IaBJk^rtXoEj0``ibH z(Bt=BVmYx$)xad4ESOBLkNe}6$UizroF)mIvysL^CSwFBT4|0L8PE5sgI;gdZFp99 zz4~k!mqlIWB5%7#_Xv2i87M3AxX6=iOO{C4q!lr6JomL!;2ySVCFk1HfcvR6Ue$Au z@(A3k(w8;$cBdd4G7xtCpUHw&VFH0 zA7-bIF;;2*xtu7Go&PTLvB39V{&~ry6;sqCWb}c-DT;UK4switeOB<|knXP6HuC9I z^yuWqR>ft1wH|Pdn|03seY2~ljE>XUU#a~n=Q1~Fx=3HOJLdH3vgPv1=O;FL`*hH$ zb%rxJ_?xeOgP3sS+%_NRJoSuL&qdXp1QA#VM?~iX z3T5Ol)zN&};f`XEU{I+S9;I~UiG_=J;-9V_m#1)DJtjXY9Tz(K>4ZYHDJHg?BBkFP zPKCv!Hw}A@F3KVWVl=fdvz>h~=@}sK4Ht2CYCXArVJ*bC=f+brU#si&EKM+3`B7vn z)Yl{Tr_CLso@4^ZU^B-yg8abaj;#lF^9*C+``48rO4ohk#n?Y-8GvZy;1U z3eJ7*@)JnTw?BdyxcwtRcCq>=`hSz$0-W*duLCC5QzLZly*Sn8ISm<79( zC{`YCp?qFd2;~!MLL?~&_gNSxd(b5R)tKdb0IZNr_kI2A(X0Gl@O`qVcgU(=>8{>6 z@%Lnu+B+_fWE=B$-c{=FVY&I%azWRLBGB1s!8NV5u`DqqOoBz;F;%UxRRb@| zeLFGb_c~?%vxyHcbY(1WMC!&Vetu*s3uhTh1$=Ud47(>Q*}gisQBl-TMeoch2@639N!J!>TJgk(v)GB@`>+zv9q~`Pci28sy9$+r z2k8$VUlLfZs!1O+#57L-a2mKI@1y<0e-4W0D2(SVynmSljRU{czY6&7|I~qu(CEGJ zb9{NOK?>rvJ8%-Frad_8vaTH*vTK|EKRWv?L@v=hwlP=KNpN?*zY_WHadFx zdg#e&JT=0PYK~*a?A{|2BC_Ez{{2t)3)4>?G;n=RelIJC_El6OzyyrU+!T0Zd_w<# z@VUY7zem)(NGJs#IvYwC@puzA(Ke+ZNZygiY0)PMQbIj867IBEw@qDJzd;dGExi;X zz^)&bOLRtVrAYBlUk(1i$5k=w_tUSZ5KtAXs{)D8(2oaEn+`{L0mB(WY5oFi=h$kS zrIMUFj*jzk7Es49Uns>0+DR};wEXlPlY%6CbA0<@0g9_ijbcyzzRONT<|E4bPEJPc>qi$A=&r%e=DP=`pbG?34I0T|bLFp# z-%`PLU6=gK>9cZ*H>DCSi4ZbjgJOig#VxqeBNdU`6Q2~_1#>y?R5p`ghJQTrp!DW{5)Aqc3W<7;2zls4=-6|8Pq(ChelDAf z%mSFm{4(lkEg^bwqd&2?844!;UnFSbR%SSMx_VMjO5m~;sASaZ+D=uTahHv~13)(@ zl7M8=<5K;+)byUU5ZymQd-Uwhu-n(?KD%T-djWIp&UTD$U(kWwB1$%_-8W9#FTDPU z0l>X#MPuEWu~f=yn;~ln9qmwmjnvi&JVG+%#PBGgz)kkkbu#d!N39N z{>bHcFmVG;-Wj=h&)_8`Q=r zLbDkw9Q??bzLH;nzx39@XiqKnk0UB&gHQ#!RaY!xc%Y_g${U$4cX*(0r$8Aj3K0s} zS$Yt=`Eb=6_6z*DoW~Ge&4F3u#oV5!Xo#bcUVYoZB~Jb9wb;8LPf(v?{?uYn@Ha_{ zb*;lCBlkOo+}+;^Yx0CeagjBY;dFYzNblJS_($Z@Y4fbLmSl*|FW23=+qx!d66-cU z@X-z_Q6LX-tz$s*H%=^nipv#QCy4L#y2LZE)Fyl$wNcYmu2$fbq{G| zzqW^mMT}kW#OK@Mu}ZnYNT6&vZItoEwH29ye)|JFW!3w*i#Aps6gDf4I$It7QN{5kpsj(i{$?9;w!TZMZqs4 zi1NpQg})YKJf_Blra%?<`g#-vWd|7`R>7I3vWbFiB^~5e`&6sQ{_iC4Ng{bniZnnF zve2JHd13o3C>(W{e}^dk4dqiJAhG>vOFxkdy$LtqNd6{<+`KsN-WL4pn*%Fm;R42g zqxgSiHGFAM;%xC4=uLRVXW|qSqcsb}|4MvDbkOdZcOFWJi}Qcriypw85*esVc&06l z>m<~L(y=RRHLF?4_-S0wZ`58w#u_8`Y+L*1!Lz5JQ)SU7XvkOX;TOU{5C$?e=S{c} z;Df;-Zki)`O?!JaLxY32! zCe}K~@)drIMN~3SXzDT;QL|L^x&bBh$XI_pPVj%BGga~WuPs^La;qY5gsRwHOTebp zlBoc3)8|4UJIZJa*U$j1P{Ed+D=F4*2F-W!@~t#5bIrm9P2LE{c7JzWq!rpg6>FkR zd>6yvK@QEx7%bS+j}-Zp#o!W-+6Ijhqa>5lMqu-GPAC=SOKqa9ONO$__n&??n?@_E zsTI=ZfWn25dr%8=NHHX!+d6p{p$#?&6oAp7d@w>pW@+F}I+z&pApd(ha>gkXHa9@a zAHPYz!`H3e2!ZPRv^kj)POAUpSv1AhIC?@m%pWmCflVw50sGRlaDHX$33$(?i1}Vj z$OwA$ZtAWHcU(I^I*%h~gw60a#}zlNfdJ>?q(eUfT|&^y66|*_eVnNW$Rh*MG09;4 ztNmG;PivRvNfFlw;B~f5y3W@EjrWcZHqSq?^`)=!!-B81WOc^VGt1I@HUL&-Yvo?v zJ8;MN>bkdOX7hUD$}rjDvYp@F!vca!kCBm_4{!V^1j9BV^+;CP=iNjCW&PY@u*72C z)AsSqZVzr0HnwRx9+U%$k=3XKe*}$1^_D-!(4ihdUZ0Geg4W%s`Ym?v@vM#C))v_m@wO~JzL3k%1gL$K*9oWG zPxb?@=q2?fkIFj*7M~;=W=exLlURRk0(g0jpxb&I{uKeN<81?_&^rvwq1WT)xN_L^ zFd4-_)x++1e#|`Xj<9uj#8y=^9{lxDo$Aj#(wCcYL75z)MqQlqmyh`=5aQ1DCXda* zuJw)|m;uX_%Y3xAE0d{*Sv0G4o#2}vR+sXS{IHVmBtr1P3vHJdlI?Cal4FN`Ez`dt z{qx4m+#9mi{l!#%Ij@3bvt#>c*s z>N8Yq?kxVD6IO&#)stGcxzzuh^?Mwzd|bXMON|b}5WkR;aI4*t4l|{VMjnv+ASAfz z_(l&6@s4dpYVkiMq%$RQGy#wO&7=50Y39zW@Y*4pwFVL=sk%QMaZWTlXd~WPM4{!QSok=aD&v7Khg<__`-cs2nE%98E~dHs#+RZw|zJpHGa%>%AO za)y?_M27C=))7nlpet(xR+YA?gTr^udTG}zRHFYx$xn{{W-;lk4n~ekX@@>4E94Tt zd~I*_yD*r7h`D6OuVmKeeC}E4iCG5$kF%8Sa15Z~Y8d=hn={iLmWS^+KkU(<9bPyW zUn~bM2huyMgN1G7L^&FxKwHp`nrFq$+ai0npI*@K?0mRwz>DOhJ9|$;Nm%}qymmfV z$knr7{gmiwCfU$G9?V_h3G1ELm_)d+9CSrUPh39b{21za`nAwO#C3bF=0SMw*w0-M z{nMYg)WiNHo5|Vx9x;GMwpyETrcj!xsH}siop12x!^!WspWA+@U8Ua0rd}Hnj9n47 z-qPS18m*~B`>GzTZN#u-6?2(37SK}^xCmdrG8;(4p!?Dv)<-T0dZhFoocl6aaVDwB zdZdim{YLb!Vm4IWVAmOaJ38K-w(u-_qyaqd)n9y{IyJZsZh3vK*c%U6U~7dp$j^h|U-A6nSI zjw?>xQIVm99oGT_H~$*j%V<)R2;SPsSzwXX_E%-trR#$;620$L<%G11z&BUss*BGz zy$7{jOeX9)pkRa_{!<-A9nT`}h(i#oV1zFD#p;dtSNO0ns1htbf#IhSAfyYALMdl} z7KWnnY8R3s*`g6&MF873MSn26oz|JMtL8^pZ<3h>O3y&`CIAvuyRpuWV zBbA~jHwe; zs9r$f{$2)?Kc3#d*j!U0OCk77tdL=7%U{!)>fuwh;%Wh8Z`1#GG8noSLpZkKQB14N@$3XfsYfz#HjqeOd(j21C(_ilfQ3G;Er{FO+ zvcZ$+R8d(xDvK8UvlSzgeE^!G^e>T&A6QX)>buNE<(Lui~VEsRs)OFw%SAvyEhpho}5t7xXc{8A*8U2%>yK`Z?bkv?#}<_pW<4XH&y% zlv;S>!J0^1`}ap@#c(oRb<9)wI_O8<@gt3wOuBf$TGTK8=bg2~6~*&2U}<(dFxPyH zO3xDGBX+vWwEy&1r$NQXP*^qt;vEOde$b)XMTUyyaND5=vBdVImze44P5zj#f-In? zQkdl^aKxNR2LOo@TOgCw`d_h|{JFmhH)$bs`=_`U;?i~U(g4ELqhO1{$tGaQ` zrM6?#R2m>IlcFz>;NuTti#vP@ykPXN45=c%>Eue>U9%KSPMgplq=lKuf67wYqcQs_;`xEYt=hL(;tc!*K%#p9t)O{OL~ z(;ebF^;KT*NIM^0Ga8v?uY*}}mJZ2mR*uP!$W$ZkH!VxkAd?SyT- z=}D>6v1PEGV8&dEC1-YJWo4NcQX&G#+SQ09+CzyCZHe>T*o!K<266d@?cGf}61O>j z%ripcYvlo1+$!*S=2ro_(ZJ63p{;CfLBcqq@XMg;7RLv(9bQ>Vxq`9n!8Uq6%;y*> zf};1bwjaXT@B>NP^3#|Zjfr18-7tL$s!XVeG`O=%H4=Va(^tH5$0Qz7iml{f=Li3* zG`8Kw{;#x2Ib;`qH#;aQMYF$XxMz)5!)nj+j;u~vpSA8lIx;Dqm^k3fvsG&l{ClWK z3EXozejG3HP@=0VrcNJ zit*WjwGQq6p`ogF<=H(piGPh9S9mc!gLj}6@kUI^af&1(LZJB800VF?ir>^;TtpVv1N$$w{69Ug13PcmhN9h{ z2uF>tBM);>H&uhnhDl)?Wq-B3j-|V$*pw(dn=}_GkYFlz%OIJt!|W3w4Dh}V6+JJ> zZf0h&h0NM520^+#FNUpL^33xf@h3n~o|c`f=}!1r;x#vt`QjY-QZ4WJ7tmHo;3q|h z2BXjv$KMT?RxzOAQoEn!D|z3r7vp7@zJU00R?@}OBpmpVTYY{DMW}aBisynw94th# zRO*ffhKNZzSN_}<=hdT#?3cHU292!Bw~iax$-(#D#?4=xT=hC7Ib^xK|E($KrR64@ zhWLjjVq+lSR%(rWK`D{t5})CE`TbgRh%1IZmc`+1jW8!Ghx^3tx$QKn3remUciZ@=6=>~Q z#M?#nSV0jPKN+)Vb)8H=akSA*&@_GR;u(v3S$}tqCW>ockkArRzkfvpA0i0@w@(sN zTDQ?PHi6y``zwzN(HGqn+AmpVu^zdhZ`S9{TZ$FE<-UQi@9mA?T6kXWOQ++!#s7-c z%HfuUS+n74SKR+s+*?LP*@kVSii9E{Dcve5IDkmEgw)V2ICM%Q&4AJ=HApv-(hVvN zBOzTX(xpgADC}!Sed>MpT6?eW$M^hjJ!@vT?yK%IkMlUO@cDh@N{XMFL)l2z;20Z8 zv5SS)M<>oC)mwR2cTT1i-+q0SOw_ueJl|Hp?Cj-_G`NRm?N~OsBXw9z9un%N$7kHv05!l2J_8Ppdb12FNY~st1yQ zuaAM-beo*Om}>VVyfHQ?VrXAGL@EbXLFp%2a;jk-4k8s6DGPC^tp4ux_20XxM==Rnd#tKgoO18!+gQ`u*-)zg$aMQQ+jYP`@ zGsjDrkE+SOhZ9B@>|!k-&_&M zof$2P%rJ20L)$vNs6b1*MDT*&Yx}<#6Njxp$4A-Q z*D)157hP}oyHdu15bTfLUb9^u4!w^K>Dg+ft1wg@3pp<%0G^KGqr|dRJWBM_t6?ik z!|7OuxnL@isw^#3!jzbb&OJlHGAk#VlW;!g1K(#M7$NnI9e6nM;Zrca*8U>gav zjx}Y85br=%U5Zeru!Z^HSI-)t$5NBUW9b3S61;$<+RIT@w2vi4x4e|bZ zfb>!`YYaE^KdP9wR3*#Z`!8|?HzGhNTf&#riUSf9lL`<-|KU;H{Ef)~PM}6#Rd{ta zfg1>}|7$}GaIOZ5Nx(OLd*A;P#VWHl46t?^$m_^xtkLCaCEF_e}j)$|EL#}aK5X-mWr+!cp6{wrnl4&0l z(s(vea^}-N5h1e|(<=TGSe6mfVNcavuDX!hx9z0sq;o#+WfLnBSA0y0B25KAFtlAm z$`Rxz1xf+N68>3_m>kkwfHhlLpCoU^uP_|bHD~5MBX!q(MWqApS1tN z;g_bF!qHF~K*|HaD)hpE8Gwn8w1^Fa3iqO129JMijFWH8){Fa1;l+ip;NMB7qo<)r zG1~_nnAj`8o@4}v1RVFi&5`ekrX%q|MR5B@?I!T(s|yENQH1IEC~#nj3F#Oxj&db@ z!&0(5y}S&F`E13sUFGqVxh&tBH{w6WUGscy^1@!oIf#rrHF#@bf$_9#hJb!AuQ*+c zYuzWZW&XUnQLMRg$V%5@fhzFA&zR6^4~`1qHvT((Gaoh1CDL0 z?&&!BwWmdR2V^*|l0(`*;pg67k*tPKqi=Y(mEmGxHV=doXc%0qx_2#tM8$lFZFcl> z*Dv~ti}VDNujDo7*fbT^ zh9Yt`{d>Od*Q!7%S}exiyKZH89J_DahlMWPVG@3MpXk#Y`Fo5Lfo`{m^&W{77ik|m z>a0bsIeI6sIp->8pg_41Q4emd#4Qjdw(UIQMh*?hZQ?n(C&>bH0~qd57u4=e1Q20k zV5Olhc>C!*wRY)IFZ>eD=(W^Jy6W}E1ayU0LkuV|?YaeT+&3>Oyo~j#e{~yME||mz zDXCQb-use(?CdmgMLT$5y{oa?mTCQ=q7ef#;P(&Sly zN6mT2Mh@x0vO`qT=uwe*7Rchr7HYbm*jmA4&nSK5&NWg`Cg!Y@0FS!T@LoQQw;1`M z^11V2DRrGIyymc1&$u(gYUO!wgpJTki6b9kopP~{;bFucN!^ATyd=3>OBqymZzaI+ zQ}e;za3bO8f)%hgsT@`{tH@c}hoj6KkkbVFqF~frNga`c)x`oQ;=boT`FSaR;iEv3 zl$gof?G@lf1n-)OKDgiac^=w+tE$5f8#W=$?S{}Byt8CokH*YEOEx*9+6&gGC#--| z(YFnt)njW}vrvXy5F{$yd7%bPQRYsv426WL z^@&r=it4+#Y~|xmCzvQ2Pe4V$4@vdUs*xfr_`4HI7Z+V8UvIVaOIa3(!P5%UqDOGc zdm28z9q%-wK~*yZR{oE&sPwL?!$gFZVfUC-K=^YCd~K58(dho+k#|XCche>gr;Ivj z+(Vx2${W{`UE~BZ?AbNPc;7mEPxX7SVluL|;gHnpEA&cOs_rc2;K#O(&=UaQ~GsP!+Xw})T7#7_)e0v z4%eOVl>?fOKbaNrKL1jUqkk{>=kSOWE~ZZDv7%ZA?-iXCPnH|&35!O~#v0xD0hQ?g&M%;cC+F{rWP+tI(YjvXy=oaP3qwdNgkp!9j_VF3-DzxbV^$SH+-mNJ zHO1x5d?2jeh;`X2*o2NcE$JvHRpWUA(x;Zl18bO3-j@<3Bd3!l$4uudy_~xGom`1$ zR|i2ZHzh?v8k)roWYq5pu0dG-sS;AM#nEcH!OX)M1A=ol(yLF2UBdG?$=o16Q6&_# zgCS8#@HhxLMKa9~tC0r}A+PjYIkN-Ir8AYBVitmaW#J=fC%tWMSkb(#tfft^Vtvka zOsdLcgi2d&rp)kU|IH?14OKxm_2#5EMCfYTT@Y#Wg;StW;=inh>PyD6!2sLHxsv;_ zljdRLc))|%uO&F~^2j&%bG=^3jk>RER;{9JH(2UaWMOPL}e^q+P zzn1Q^t16C_s2+5YJPBJ{6Wc!;8Z+*v4&~3P6cCX(r7#y9h%Ma4UHhnW__(fDtH9K6 zEU}2LI!b&Q<2Y?n)BHUEOsZ(kx|@fn$_uqcZNHac}PkmjGMnPha@;VWgv8C7buRkQ<8e z&qc!oi~POpigrp)iB&6}emUN6dHDp;xtyj}1Fp414xJa8w>LPgMJ>(=a)KYS6NYJT zn=hhFSYYw5*H<$X#!3H({-TNK$ z-HRA9XCmo%#i`5r6dy=qzub7kH|zT35(gJQ{&Yvj{*%}vjT zIG&-t904X!*h&;Vg7=Vl;cXKgz{4Z^#Blr^XxmC3P|jc0he*riKr^Cs$~F0^y1AA>8@OT>yw#~Bp@c|P0$?1^7x!;q`yln~ZljeVD$8(i zFK+D-Jz0@3MEqdvO9XeDnY(+YbgnMFiHMJDy)6 zNlskOz-eF5TN8UZp@IH~=Bs|}vSw;~WOdLWn}KBY-fU#2-Dl^t7`=uRGCq)aaK(^7 zK}~v5{&WmqaKUB;xIK+$Z?i+l*a+{LgZ?4DTC^ZTkv2cUgyINN2FGR?XCz&_jfxW} z+;I?AiEfL03u-g!bVK{Cn(oV?h64pE;KFdZQSQB{d5}N^+*6n`8OBqEO|U!Hd|uoZ;xhPaWk+E_>ln^_9&#yHf2K=BkM5v zuTk34Fzsz>{y7msm()_mZuKT~7NUf7E#FPj0GU zdc=ty`5^!$JH+4Z)O~<1S$9apXstmpSD_GAx4>WI^Im7SiwDDNe}ko}yn~rq|AVR( zoDlL$7P!l-DTr&dLe57!Fu9tJJGMmuF>Wd8=| z&H&ZLN|jX%C}dT!@_#ZH3)j`qJu=W|CUKQDHcO(fv&G`wy+Og%y%HVcSC2oQkyfCc>M=bag`WV#U&1f& ze7+tlbPm5=MlL+zygU^fZFwJg7~;rJRL59{c{bSjP~h>4A_<5ssoR|pA7r)-C`kUt zD9SZnYc4~itm5oJKFG1te{ibAJZ*4y^qJXZ<*49=e0%+R=azQteTU0CZp1E9{M!7t z`KjjSq_D#Ea*I&Vmp_a-T{BYX(sKz>;8A~%Y#oM@kQF^eXgH=^78viL5t$`l)YmRw zgYs{itUR=U&&wOBXCY{viFpMx*xFM5x9kI+NdSguRKLL27Vev#$(OtoL5FPVq^pFy zfe@je%-M*$&a&o&vK8ngLz`~;uV9r`5_kc2m`K-X|3zLBQO?XIGyF`Sqaz4W<|Tw5 zy?#q zb~jOqp;GA~MUh-*7OWO&X(aM@K&+5W|dKeoTpuRgeD76Wf7f!jBe4Q}Nef!dw$6?W*9g$$Y}Vqa^)rUMIb zFcv_G*nW12+jdwZK4I!|rXoBmYREED5W}IF_k#@$Q{f1=)JB`Z_gWzI|Ljjw%tDVJ zUGg7a$pVx-AFfVzY|J!DJ-xeoeN7OMNP-tFB6_ODQXy#f6cIgaP}NtfG(u(WnH&_Y zz*Qig@-CIoUG)dqK^`!ocwrW|W`=&Oe%2?f9=Z}y<*WX>>4BXO*N5D-T0$3y{=KxL z)~sCz%=@`KQo}Uwh8Z>k%B3!$1sinEhBv zu3sE;r8#!`>_(y1FbmN1Qzt~0>2}Y}jl?W`B^!svG0m=X-uBx|Ivc&#ImbQl%$*vb zCD59y%D{;QGOB|0?n(ro<>RhI4M#hxWr1ZD=Ri9Qh)a7h(Kz+4fI^VnO8DN&1C|Pa zKY%Jdi+-B)aDxxFGSBx}DCe%(H^>0o=F_Wm_hz1ZxvDBa6#m4zTM4W*iifGWT?cj`bQFh@uM}_qr<@PttSoLu^H?1ZSR> z^S{Y9Gy7ce&DRw^L2BFJ_&a{E#pgtQzZl>)xn=3Z%7;p+)@Y&G16Ro9v zRZ9I1ZZt0|bbWq`hx#!Un@NbzWRd9_E@@E+(Byu4Ts5!q! zii0v6P!QE$UtWN4f4cFnPXaKo$a=R;%jIgwywGGTe}C%*Mrf3i%BB40z<}-=+^RLW zbUhlJ@MrAbzfGP+_HFt_V4}k9V4&A>aA$lHn;-yP0IzHBqN2tPG>8NBHkwSaI_bWK|3A7|ae00J+8-nPa4x#RSWsx+z7O&O@3n z3K}OHB{YOXW;=bpd*;>6sTenN_$3vlg?%J{b**_K<6)M{{PNxxu3;;?xT%YQh=Bx3 zH=yc=eZVej=~|9W!%z*bv$GlFQzVh*8TW}`+B8Ttz9cCQh7}BpAj!I|&*inY12Q0G z0bhhOfh}@X1IL=8P3h()0mlvVgxSF4n-fugtNg9=$Lz-!B2;x42MjB?-WOqCau#|J zVDhY}P`Oe`WRp;qL}I6i%iL?TpK)?_JGU>-eljL{IN;0sMvggBdYjl>DCVO=ryUb- zu4UzwOfH=M=AiWV-1h1P-}I71eYf>#2NtGYhVNWUNPaAI)M0dkrjO{#=&Pm&tvb?` zP3d>8dvAsIvzkEF0L=&dIxv~PTv&V*YR(S54WYK9er8x3!d$Z>OHF@l`DX0;lj=wY z3tQ2ZSW_**l&GH`nLU#6E-xiiX#KZtSR`pc`B_xeZaEa5X~%mm#jC}XjuVN)cI&50 zZ`jR0TdI88LjZHAT<94_k7mLNSZ@a`fa!?k)P&XMp%~1DQ~xgNXk^Z^KhK;2UX{0 zlJpQ$3WqiZNZuy`cSOGwY~v^e{LQLPmKRKHFu=pLztea@u;Ax(*tEU}^ZA`wZ6*zx zYUZrzJf&m~{e{PmL-nwXHp`2HO=0)v0_Z3e&9)d;u2cJ=`3sR!x^>EQG6xcw>fMB^5|(%GzlLN9z+xk{-gGyXmf~E6Y80z7Wi-$^3?63wNo( zyUg&SDrkKoq7p_15&b+^sVhmlG9`(`!eb9dndvZa$;kG|iXW$9h%&AOq+sp$Q$%Es zj6{lAVeS3j)nL1#R--9{B>Ud9H~xJ;-G6X-4rYAX>bZCLo!App-VX(gUdy%VwM$05uD88bm4fGZy5J^^szvS zG&>ee!uSd0E51I;kxvHd^xp28jwp5_pzN>o2Bv}_o|1NwC`)Jfg2}iGuy3NL zmQ{pdCRa5pj;r=$yLR$=bA4Q4N+7iA>a(=lXh|G&6~<-53?=yW2n0rBXi8Ds)HnI> z{Ddydj4xlP1R+XBYCr1(9N?2*TMsA_AHr_YyL=Bgz8pm*wh|sz02vQLP`eZ%qXQAX zTbRF`zbuK1u!5`)<@R7oQtEfp%R>=`vN*xFEc(CfB0HgE<4N=H=*E(x5cO%oj$e{+ z-$^|bK=2LQffh$2DhP1!92>i$IohJkLYx4Xi@~A2EBFFPKm=D;6$)Bh2+zk?J zGfa8;%{J(x3Z4@s6R*v35vRDLfY^7#lK41vqD0qw>>Zy#lUGM#hO4ASVHjAU$I!U# z6>;Ok2}Sx(H|ZPp%LdMVtS}|+m*IsrE;MLbd0Zy!MALZ{pO?HfNR4duk&Ve&wB2)LCX+K2WmQ=RLui~0l_0TI$eaz!u;6UMfFIOw4{%kx{^PajeXYWv?@TdEwepHN@ z@8417=3PvnV%D;(az#`Y(qa?c6tB*JeuT-7IXOn9HMJd?WPOt8igUor*yx}Z8XojQ zj*g3P73&O&aS*G<-lQ^6zxy6EVS;93_%c{vtcbVkW$$I49~&fxwSQ&#=<+J;tD7uI z6&v-b{we``#1<=2sU-4l;nYL-3d>I9)V&Mlw9#pVh*IdJ*+Uo08vf|X7tP0oDugae z(KYzQ*zcPz2OV}DZ`Y*_4Dh7kvR|>ZFrGQUNpxzs{Ols)0(<*XQ31!b2XcLVTpU8k z{{HepkB;6ltcVZDn4nikT7H?)+^}d4J%vSsV>Nfqg(reOHT?UjkCyc|D-+0_sc|O1 z-9De8yqM#61!3PaQjPI!=PS3_SmkE0YI_QQ zMtqwY{g_S@yHWfP&Ai;fUpHML-_4;!2W*3`cT$+?H2vYA#I0@Z>kcq-h_J28N@?{W zoo}@dl3z{6LNETNkt;FGphJU|ehl|?$&QL=qh2IHmMyv~SVMr|`5bF}ZRti*H8oLt z8JP+-0X3n&uoJJg^iM*n5~1i8{Q4(HEce&s`!cakzGI$~p4}#9ws^kc<4C!wcFBp} zaJot3;i(~?UsYblg^6#M&vQmsGwJfqw$0eTeo36R^c`NJO@LBp?DiQGjAmVDg}%h7 z|LE6jVsT=^pOB1*p%t#H?yWnEG=D5~?(lH;%ic#)AA)TW)7H|IHWPoS%0sK4l#hk{ zTaP$BDj#S@<*1mB-X&YNtpTq?=awW#8M{6&Y=TuOQvz98s80vu&peMfSiPb$cp)yl zmap4t(g3%(xIzQY*8k|GdDNrB5X7Rwfbxg12hLe!7u!eV$-{<*zU1xoWG!sC5wLeQoHXY->=&o(mm|n`$~NCtI&DWz+gj$7=`e-SVmCWCrT^s#HKSm?F6w* zr`9P(;n%pg7X`OJ-xosYf-o9z;SRm<3c#5z#zz(5eS;7uX4CYaq;jfJvXe^Rwq{Xe zWS9P=6>t$7j`&`lKLnu(B0^3Oa8>RoOjgW?&IG-DAnXv)b0IUQp2qy$qoyXJHpz;` zt2yu~p*f*YuHL|-Y>B6Q^wl*_ArElP3f7#k90^`%imf_^Xt-9FzS;`VYu^(I)6gPn z{6R#vJl9K^S0&T(8Um5ANG{vEO?5`3E;hrF$monOfbrnH%2`z?_JIUE10}0s=tNI8 znP!_*IlUJ*ZnrEYjX%Z{qZam8&P?`&rT1rvx5e>4eBST-nIto|7Bf97-RByIgMU7I zj9;(l1**HD)0cP*v}%N46ZOKEBFBd|QWWpbs-8FnTg(oxS$#518p7xnJ0{Ow`gBpM zt(~NkvtjhfFb6?7GScQIcXN?@?t0<-$c>zoAdFxZzRT@U)w3(&x1KQ&p5OnO-e;E5 zT6$z2JB+`__-c4GHqLS>u(G6UP(5tg>un_Oi)Q&OdUJU#^{2|Zbm|8Y-9DYe0!LnM zb!PJo=FzSa-`{y=PzXo$2uTwd@gB-f`%hDD>dA~tSAI!L55XVPdocErpyrZg#|Kv< z<$d_znwrbnbN61aXhFccnUDt*=|g?}88tIg8IJmUe#de-xZPE|d(pJwCp>!;)wgRj z&iZ(Ihnm_{OGy&fKjXDV^=omsyLie<=3+zYalJ*cHHaYI`)5yP@YZB-(?@i=HAmb69xTzj@Vkn%$$OW=U0j#TiJ(P~D=*?LFAPdH_%zCb3 z_VOtrs?a(xCVjXnBnb2e_svKd5g{##!cggPwf72%28YQ84s-qIRLt^6WZ~}E>W}gL zGEDHA%}F=CbkhJfU76fm_#hnNZJ{{~^(MW{#FxhLvDPwy;tFYR5m;=&OY#T9LvwDA&9TjvKM#~6bLe(FAf?54CTrOZe zfPU%`Kl`SoV|1{V8zc5HKWZYU`AgI0Efy9Y5JminNL ztF|^MyLi*EAQ_>_dAs;=Ffg<%Xjt}%|MI7SkDFx-%-hp^kr_0;?T@2v_5c63g-~wa zBoZmTKMQS~Fm=ewmnqDacnO}Mm{_foIHL63!0yko!chz)iCwb7w^3EIy_c^1+oS^q z*b9HxCV$lI3R~p{7%X&uxBT8wW8jAPLuOYVO+!g>$MnJS%dV*!u1X-q+%e358Nyj0 zQozZ1lO=G2qWUf`gpbe;c+H|bEue#L3uNNSSADl@(I-*{$E~rZN{KZDOnL5AA1K+G zEu5TR*}Jl9W6-PzT81biJu+Ep3(hm!+;v)RW}zKy#{W3jxY)WD-=XB_>;@NZf+F(# zC`SAS!kvV-&^!u*mxSb-F5zQR-b+E{ITCTu)3dvwxRk^RgK@fY*H&kPosd+c)4Hlc!>dbqGbry^wOA9p>29Slo$ znDe&y(G&EB*{f%9qG3f}y(XJ`brx@}=$cquxFf{gIwWMn>{vg2ulT?iF3k1ZI92|5 ze7IAFF!7CH3kHV<71>3a-LofBx&3TK>@-yGGo(hMam7XsFi#^1$<_^Pgs;^{>M z+E`U7jQA9t%VvJwV0?3=O*Bt_BV&fNBp7jwANuOEukiaHoMCA=aj%Fn?AaT1*KTP4 z9KUoWy;aYjBEi2VK6F~fLUss7B4$L8;DIBYZ#$Ujye*9Rt=C>owx0>m> zlG#OEo!YLXa;J2CtSEgx&?xotC3@Q%?N`RB5^id<3xx4g;UC<6*FvP1%}bS=6@z^~ z1EKKTQ0q0(q#)RSB}7PNy3@gcox4p)!}FAi!?axpyY5#P8zvC@;BHqODhp?14jT+=bhA~xw{|#(>rtnVXr2Um8+|ha+0+^Wm zHw`9-L+V?%^HNfbuU1rV_O&;>iqs8F*kM?MGCIQi%p>-Qs<$s6-dxG5&?XOzCS$UQ zQkz?!RE^#s*&HjK4iD3#{p?3)O^&;H)=)0XfvIpkrg`JkNrtxzB8>4uxnI-R^49$O zuwOwDe%SAzi29xSiWEstl&q4tO3JE)Bsbh4TYpS-l>YHJ9rSr3XP572)ed&b)wy%W zn1h+7$i(yRcye^=`!_#7Q*alxaoaUmy-V#YrWvr-dCtKuJ>ST`VIm<}IXzPT42L?a zX(c?*dxBUavUw>w5Ic7*uB(yxo%h)YeE%!9mv{iXcj`Fd-q=$-e)Uyj`k0!{NQHK) zcM%Wf=U-KnpQUT|*_!vdu_9(C9x4q^nMxL~uPGC}b_}+;@#L8ioW`Rfk>gX}FyXTv zwo0Y~xjDh>97VZX&-V3Am>`(w6@eBOuv=oTE-Y8@F}%#u@&tX1l0om-LCtb}XOEP2@yY}gtL~eWQY8-UpT|y)IK}sGK*O1PQDwsh<7USgN{$(=oy+6wa{K%>(Wq3p6#lKZG zpd4HYreSqOmk<7B1pJ@;c9;fBT?clZ@&zx$J}K@J2wtbDaxVpA{8HV+l31a^>0gg| zJwWHmRxzQopCkL``}6dJ>9nL`d}h7x>s`QF?yZmfiC@7%-=zD`t0LamZPah>lwx z!qXP2`k#6+*;COzuucf3#!K@Pf7)&C!H_?zEa;*CUX{>Ak>Ez~pBzG#5LP%zHMTiP zikk^lx%P*{5p~(CR#6N#>7W&hmeHV>xwJ;Ed;B1Bgw9#)y6^lMwxD&YjCk!V6Ck0BVI;;=xM?#1$bD@mvz!h42@jHiW;TT6X zm#0k}4{L>8N@D~=X(|=_yb^L}5AB+HH&qmZRc#ZTYQ}E1&I(w2qoQ+#&bg33#+I^X z7Au5W4aWldj3j!1$)da>)XHS|MRbO?rYsXgE(oG&dZ^Pyg$0>BngQ68qfc43f9$Z0 zYzaw_XbdNlPohp-z}8dvlwE{Ji$hCl`my8{;qr+)j((>|ZZcJ3wiHAYi%aQV*mUUZ zoh*9Qvx99f5XDsX;`%qy%Ptv{CRix~iJB##GCf!rOcXZIPjPit=~Y|5=g zBH3rxiXxv~KDehI_l@=8l4r+Lq}qc5#`U^Lr)gS8SL)8WdJgRW-XCZrB9%u7P}k)F zt5GHKGUcD`bTxt}5mkS~%siVqFpd1i0>19Pg2ths6G3^b5}j%0LDA5xGVt!qdYM7E z{%jdqfjWaYY;rEM4H|v(m+@Ny-l#e{JwUSa=OdJ%Oasnwc`a1`&!f@b&HOh`ihcoE z<$zHtD3o*kUk|H8rJgq9x*Gm9LO(En4Wpxru>SS1|I5?OV#b~GKmVy??0b;hwx2&z zXUBJ)YNYl12Wk&YVS%MsQihdi!+DBZf2HT3ff$|9s}KE_<@_tZ8;kr%J>Sj#SjRk~ zi~Tk8^mF|L2oT>aCc;1N=ct%#_W1hP4}_5G%yTP|@7|ReZPGbwViLMsA-`6PJ~i~t z0{GA|>`HQb!)bmavtrq_6{pUY=r@*YbjKiYd|fn}Z)tjZI{Bg3%e#wYmjsep8ELKP+0`f# z{`^~2+EfHEtfXt%d1Rg!m|K?C+Y}g~VskUK=pdcHs5zm(cGXS7y-L#_T>f>6gwn8X zQoC-7ppkFi-mh9Y)%8pvOn6+*xZXDa2BG$qVadPG(i)tlU)A&N^1Y7@TalYl#Rt*9 z!)0E(3McL9`JK_=G_P{EKx?vlvt;gj-Shn{ZE8wFA2~GgKKcY1c-*A0hyl5`O)TU8 z_i4;Hv)>e}w3}v`z)GwZ|Ipxd^*llhhrYhlFL%bkftxt=cx@!NYZkURoO^PR zG+tu;)JDQf#4B>J!W>6QuT!krq|M>~WyT-W=DUy8?J{)>Up#^yEz@K9J6mY_Cr%_{ zqT)NdHY;+*ez{ay!!C`RQJF`b)LmRIk=a9a3>NlE%!+A-Kl7a6h*bA0IqiQmNtVPm z=wU80+I<_2SSOpdr}>5#b+yy*)Rutuw+RQf>_q`MhMt)Q&<3m(+7!j?7uk&kbC|gq zdiM84s@0Jo+&koVxYDWgc*=G$w0`t|+w(NF$u@(VK zAj^^UZ{Y*J872a%idJy=A94`o=tzQ3v7Sl)Wi+5QU^I%vq8Hx%w`@aUEpUOV;$o!< zN87G{UQ$;XI8A4Z>3QY1_IY`%*gqftnu>%6DFgN`;=z6Fc;jsmDZO>kTk?Nhj9*DT zVO+vXBv*t(kL@3O&${{7FMKfOMtodA^Gf_la{>bI1`L_r&OVuefkC0o(#iI3x0_d^ zJq(EerPiNCqs1NqmynT!K0s0+v7g}?yuY&n(H6F6S?l0cJp7eP1gztgoK8NMTNzRgGfQVzvp!A z>6&ex-{_INf`9{UrM&MO0-MU8|!M5d% z!C9Wm{fU`BmRO9x2iG(FYiA|kTpT-X-&?;f(w`so_Fi7tT~0PWJHJ#K`TB6psbK2@ P_)p=!icGnbN#Oqj2TCJl From 83a64db64d4d42668956497c52bb6b48b3e369fc Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Thu, 14 Mar 2013 18:41:52 -0300 Subject: [PATCH 0113/1224] Bump version number to 0.3.0-alpha --- build/ScriptCs.Version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 15bea9e1..44153387 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -4,7 +4,7 @@ 0 - 1 + 3 0 @@ -27,4 +27,4 @@ <_Parameter1>$(PackageVersion) - \ No newline at end of file + From 5ad693ff6f9a39401a2703c620c7fed84b8392b2 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Thu, 14 Mar 2013 18:41:28 -0400 Subject: [PATCH 0114/1224] Append the date for nightly builds --- build/ScriptCs.Version.props | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 44153387..8c18979e 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -9,14 +9,17 @@ - + alpha $(MajorVersion).$(MinorVersion).0 - $(MajorVersion).$(MinorVersion).$(PatchVersion) - $(PackageVersion)-$(BuildQuality) + $(MajorVersion).$(MinorVersion).$(PatchVersion) + $(AssemblyInformationalVersion)-$(BuildQuality) + + $(AssemblyInformationalVersion) + $(PackageVersion)-$([System.DateTime]::UtcNow.ToString("yyMMdd")) @@ -24,7 +27,7 @@ <_Parameter1>$(AssemblyVersion) - <_Parameter1>$(PackageVersion) + <_Parameter1>$(AssemblyInformationalVersion) From 598cedbd3af2100d0e5c1b4a423620b976b3e88f Mon Sep 17 00:00:00 2001 From: Matt Wrock Date: Fri, 15 Mar 2013 00:43:07 -0700 Subject: [PATCH 0115/1224] adding chocolatey nupkg. This bundles all Scriptcs assemblies in a scriptcs nupkg. The ChocolateyInstall will copy them to `$env:appdata\scriptcs, use nuget.exe to install nuget.core and roselyn assemblies and will then add $env:appdata\scriptcs to the path. --- src/ScriptCs/Properties/Scriptcs.nuspec | 25 +++++++++++++++++++ src/ScriptCs/Properties/chocolateyinstall.ps1 | 21 ++++++++++++++++ src/ScriptCs/ScriptCs.csproj | 2 ++ 3 files changed, 48 insertions(+) create mode 100644 src/ScriptCs/Properties/Scriptcs.nuspec create mode 100644 src/ScriptCs/Properties/chocolateyinstall.ps1 diff --git a/src/ScriptCs/Properties/Scriptcs.nuspec b/src/ScriptCs/Properties/Scriptcs.nuspec new file mode 100644 index 00000000..e2999295 --- /dev/null +++ b/src/ScriptCs/Properties/Scriptcs.nuspec @@ -0,0 +1,25 @@ + + + + ScriptCs + 0.0.0 + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md + http://scriptcs.net + http://www.gravatar.com/avatar/5c754f646971d8bc800b9d4057931938.png?s=120 + Write .Net apps with a text editor, NuGet, and the power of Roslyn! + roslyn csx script scriptcs + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ScriptCs/Properties/chocolateyinstall.ps1 b/src/ScriptCs/Properties/chocolateyinstall.ps1 new file mode 100644 index 00000000..ce6073a5 --- /dev/null +++ b/src/ScriptCs/Properties/chocolateyinstall.ps1 @@ -0,0 +1,21 @@ +try { + $tools = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" + $nugetExe = "$env:ChocolateyInstall\ChocolateyInstall\nuget" + $binPath="$env:appdata\scriptcs" + + if(!(Test-Path $binpath)){mkdir $binPath} + Copy-Item "$tools\scriptcs\*" $binPath -force + mkdir "$tools\nugets" + "nuget.core","Roslyn.Compilers.Common","Roslyn.Compilers.CSharp" | + % {.$nugetexe install $_ -o "$tools\nugets"} + Get-childItem "$tools\nugets" -filter *.dll -recurse | % {Copy-Item $_.FullName $binPath } + New-Item "$tools\scriptcs\scriptcs.exe.ignore" -type file -force + Remove-Item $tools\..\lib -recurse -force + Install-ChocolateyPath $binPath + write-host "scriptcs.exe locted in $binpath is now in your path. " -foregroundcolor darkyellow + write-host "You may need to open a new console for the new path to take effect. Happy scripting!" -foregroundcolor darkyellow + Write-ChocolateySuccess 'scriptcs' +} catch { + Write-ChocolateyFailure 'scriptcs' "$($_.Exception.Message)" + throw +} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index df54235d..6c9b9bd6 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -34,6 +34,8 @@ + + From 76f967e77939f8f6adbffc21940964ede283dd7a Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 15 Mar 2013 00:58:14 -0700 Subject: [PATCH 0116/1224] Migrating to use Autofac for internal dependencies and MEF 4.0 for external --- src/ScriptCs.Contracts/IScriptPack.cs | 5 +- src/ScriptCs.Core/Package/PackageContainer.cs | 2 +- src/ScriptCs.Core/ScriptCs.Core.csproj | 9 +++ src/ScriptCs.Core/ScriptPackResolver.cs | 10 +--- src/ScriptCs.Core/packages.config | 2 + .../ScriptCs.Engine.Roslyn.csproj | 1 - src/ScriptCs/Bootstrapper.cs | 58 ++++++++++++++++++ src/ScriptCs/CompositionRoot.cs | 22 +++++++ src/ScriptCs/Program.cs | 59 +++---------------- src/ScriptCs/ScriptCs.csproj | 12 +++- src/ScriptCs/packages.config | 1 + .../ScriptCs.Core.Tests.csproj | 1 - .../ScriptPackResolverTests.cs | 31 +--------- 13 files changed, 121 insertions(+), 92 deletions(-) create mode 100644 src/ScriptCs/Bootstrapper.cs create mode 100644 src/ScriptCs/CompositionRoot.cs diff --git a/src/ScriptCs.Contracts/IScriptPack.cs b/src/ScriptCs.Contracts/IScriptPack.cs index ff186662..c22f6999 100644 --- a/src/ScriptCs.Contracts/IScriptPack.cs +++ b/src/ScriptCs.Contracts/IScriptPack.cs @@ -1,5 +1,8 @@ -namespace ScriptCs.Contracts +using System.ComponentModel.Composition; + +namespace ScriptCs.Contracts { + [InheritedExport] public interface IScriptPack { void Initialize(IScriptPackSession session); diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index 91b939e0..2f83acc0 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -4,7 +4,7 @@ namespace ScriptCs.Package { - internal class PackageContainer : IPackageContainer + public class PackageContainer : IPackageContainer { public IPackageObject FindPackage(string path, string packageId) { diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index aead005c..502908e9 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -9,6 +9,15 @@ ..\..\ + + ..\..\packages\Autofac.3.0.1\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.3.0.1\lib\net40\Autofac.Configuration.dll + + + ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll + False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll diff --git a/src/ScriptCs.Core/ScriptPackResolver.cs b/src/ScriptCs.Core/ScriptPackResolver.cs index 224aa1b7..59747df5 100644 --- a/src/ScriptCs.Core/ScriptPackResolver.cs +++ b/src/ScriptCs.Core/ScriptPackResolver.cs @@ -1,25 +1,19 @@ using System.Collections.Generic; -using System.ComponentModel.Composition.Hosting; using ScriptCs.Contracts; namespace ScriptCs { public class ScriptPackResolver : IScriptPackResolver { - private readonly ExportProvider _exportProvider; private IEnumerable _scriptPacks; - public ScriptPackResolver(ExportProvider exportProvider) + public ScriptPackResolver(IEnumerable scriptPacks) { - _exportProvider = exportProvider; + _scriptPacks = scriptPacks; } public IEnumerable GetPacks() { - if (_scriptPacks == null) - { - _scriptPacks = _exportProvider.GetExportedValues(); - } return _scriptPacks; } } diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 6407750a..2c44436d 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -1,4 +1,6 @@  + + \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 78576b95..38a08ea6 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -16,7 +16,6 @@ ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll - diff --git a/src/ScriptCs/Bootstrapper.cs b/src/ScriptCs/Bootstrapper.cs new file mode 100644 index 00000000..d40b8c1c --- /dev/null +++ b/src/ScriptCs/Bootstrapper.cs @@ -0,0 +1,58 @@ +using System; +using System.ComponentModel.Composition.Hosting; +using Autofac; +using Autofac.Integration.Mef; +using ScriptCs.Engine.Roslyn; +using ScriptCs.Package; + +namespace ScriptCs +{ + public class Bootstrapper + { + private readonly bool _debug; + private IContainer _container; + + public Bootstrapper(bool debug) + { + _debug = debug; + } + + public void Initialize() + { + var builder = new ContainerBuilder(); + var types = new[] + { + typeof (ScriptHostFactory), + typeof (FileSystem), + typeof (PackageAssemblyResolver), + typeof (PackageContainer), + typeof (FilePreProcessor), + typeof (ScriptPackResolver) + }; + + builder.RegisterTypes(types).AsImplementedInterfaces(); + + if (_debug) + { + builder.RegisterType().As(); + builder.RegisterType().As(); + } + else + { + builder.RegisterType().As(); + builder.RegisterType().As(); + } + + builder.RegisterType().As(); + + var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory, "*.pack.dll"); + builder.RegisterComposablePartCatalog(catalog); + _container = builder.Build(); + } + + public CompositionRoot GetCompositionRoot() + { + return _container.Resolve(); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs new file mode 100644 index 00000000..997cbf4a --- /dev/null +++ b/src/ScriptCs/CompositionRoot.cs @@ -0,0 +1,22 @@ +namespace ScriptCs +{ + public class CompositionRoot + { + public CompositionRoot( + IFileSystem fileSystem, + IPackageAssemblyResolver packageAssemblyResolver, + IScriptExecutor executor, + IScriptPackResolver scriptPackResolver ) + { + FileSystem = fileSystem; + PackageAssemblyResolver = packageAssemblyResolver; + Executor = executor; + ScriptPackResolver = scriptPackResolver; + } + + public IFileSystem FileSystem { get; private set; } + public IPackageAssemblyResolver PackageAssemblyResolver { get; private set; } + public IScriptExecutor Executor { get; private set; } + public IScriptPackResolver ScriptPackResolver { get; private set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 61c51b6e..6d14a061 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,11 +1,8 @@ using System; -using System.ComponentModel.Composition.Hosting; using System.Linq; +using Autofac.Builder; using PowerArgs; -using ScriptCs.Engine.Roslyn; -using System.ComponentModel.Composition.Registration; using ScriptCs.Contracts; -using ScriptCs.Package; namespace ScriptCs { @@ -23,65 +20,25 @@ private static void Main(string[] args) var script = commandArgs.ScriptName; var debug = commandArgs.DebugFlag; - - var container = ConfigureMef(debug); - var fileSystem = container.GetExportedValue(); - var resolver = container.GetExportedValue(); - var executor = container.GetExportedValue(); - var scriptPackManager = new ScriptPackResolver(container); - + var bootstrapper = new Bootstrapper(debug); + bootstrapper.Initialize(); + var root = bootstrapper.GetCompositionRoot(); + try { - var workingDirectory = fileSystem.GetWorkingDirectory(script); - var paths = resolver.GetAssemblyNames(workingDirectory).ToList(); + var workingDirectory = root.FileSystem.GetWorkingDirectory(script); + var paths = root.PackageAssemblyResolver.GetAssemblyNames(workingDirectory).ToList(); foreach (var path in paths) { Console.WriteLine("Found assembly reference: " + path); } - executor.Execute(script, paths, scriptPackManager.GetPacks()); + root.Executor.Execute(script, paths, root.ScriptPackResolver.GetPacks()); } catch (Exception ex) { Console.WriteLine(ex.Message); } } - - private static CompositionContainer ConfigureMef(bool debug) - { - var conventions = SetupMefConventions(debug); - - var catalog = new AggregateCatalog(); - catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly, conventions)); - catalog.Catalogs.Add(new AssemblyCatalog(typeof(ScriptExecutor).Assembly, conventions)); - catalog.Catalogs.Add(new AssemblyCatalog(typeof(RoslynScriptEngine).Assembly, conventions)); - catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory, "*.pack.dll", conventions)); - return new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection); - } - - private static RegistrationBuilder SetupMefConventions(bool debug) - { - var conventions = new RegistrationBuilder(); - - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - - if (debug) - { - conventions.ForType().Export(); - conventions.ForType().Export(); - } - else - { - conventions.ForType().Export(); - conventions.ForType().Export(); - } - - return conventions; - } } } \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 522477a9..53715019 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -12,12 +12,20 @@ ..\..\common\Icon.ico + + ..\..\packages\Autofac.3.0.1\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.3.0.1\lib\net40\Autofac.Configuration.dll + + + ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll + ..\..\packages\PowerArgs.1.2.0.1\lib\net40\PowerArgs.dll - @@ -33,6 +41,8 @@ Properties\CommonVersionInfo.cs + + diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index 0c45fa6c..a22262dc 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 7ac4d681..2f142f9b 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -21,7 +21,6 @@ ..\..\packages\Should.1.1.12.0\lib\Should.dll - diff --git a/test/ScriptCs.Core.Tests/ScriptPackResolverTests.cs b/test/ScriptCs.Core.Tests/ScriptPackResolverTests.cs index c2068f28..b64d7cf1 100644 --- a/test/ScriptCs.Core.Tests/ScriptPackResolverTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptPackResolverTests.cs @@ -1,16 +1,7 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.ComponentModel.Composition.Primitives; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Moq.Protected; +using System.Linq; using ScriptCs.Contracts; using Xunit; using Should; -using System.ComponentModel.Composition.Hosting; using Moq; namespace ScriptCs.Tests @@ -20,7 +11,6 @@ public class ScriptPackResolverTests public class TheGetPacksMethod { private ScriptPackResolver _packManager; - private TestExportProvider _exportProvider; private Mock _pack1; private Mock _pack2; @@ -28,8 +18,8 @@ public TheGetPacksMethod() { _pack1 = new Mock(); _pack2 = new Mock(); - _exportProvider = new TestExportProvider(_pack1.Object, _pack2.Object); - _packManager = new ScriptPackResolver(_exportProvider); + var packs = new[] {_pack1.Object, _pack2.Object}; + _packManager = new ScriptPackResolver(packs); } [Fact] @@ -42,20 +32,5 @@ public void ShouldRetrieveAnyPacksInTheCatalog() } } - - public class TestExportProvider : ExportProvider - { - private readonly IScriptPack[] _packs; - - public TestExportProvider(params IScriptPack[] packs) - { - _packs = packs; - } - - protected override IEnumerable GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) - { - return _packs.Select(p => new Export(AttributedModelServices.GetContractName(typeof(IScriptPack)), ()=>p)); - } - } } } From a977f1395b4a5558c8d5509c06cdd77d1cab5cf2 Mon Sep 17 00:00:00 2001 From: Matt Wrock Date: Fri, 15 Mar 2013 01:11:24 -0700 Subject: [PATCH 0117/1224] adding powerargs to nugets that chocolatey needs to manually pull from nuget feed --- src/ScriptCs/Properties/chocolateyinstall.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Properties/chocolateyinstall.ps1 b/src/ScriptCs/Properties/chocolateyinstall.ps1 index ce6073a5..923c480d 100644 --- a/src/ScriptCs/Properties/chocolateyinstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyinstall.ps1 @@ -6,7 +6,7 @@ if(!(Test-Path $binpath)){mkdir $binPath} Copy-Item "$tools\scriptcs\*" $binPath -force mkdir "$tools\nugets" - "nuget.core","Roslyn.Compilers.Common","Roslyn.Compilers.CSharp" | + "nuget.core","Roslyn.Compilers.Common","Roslyn.Compilers.CSharp","PowerArgs" | % {.$nugetexe install $_ -o "$tools\nugets"} Get-childItem "$tools\nugets" -filter *.dll -recurse | % {Copy-Item $_.FullName $binPath } New-Item "$tools\scriptcs\scriptcs.exe.ignore" -type file -force From a81f5b8547c448e578c572cb628484bd5cca1e14 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 15 Mar 2013 17:00:27 +0100 Subject: [PATCH 0118/1224] Added mssing namespace imports from script packs to RoslynScriptEngine --- src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 027db789..daf36f9a 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -36,6 +36,9 @@ public void Execute(string code, IEnumerable references, ScriptPackSessi foreach (var reference in scriptPackSession.References) session.AddReference(reference); + foreach (var @namespace in scriptPackSession.Namespaces) + session.ImportNamespace(@namespace); + Execute(code, session); } From c0178f478dd406ec920f878532dc69596a0905c2 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 15 Mar 2013 13:15:48 -0700 Subject: [PATCH 0119/1224] renaming bootstrapper/composition root --- common/CommonVersionInfo.cs | 21 +++++++--- src/ScriptCs/Bootstrapper.cs | 58 ---------------------------- src/ScriptCs/CompositionRoot.cs | 64 ++++++++++++++++++++++++------- src/ScriptCs/Program.cs | 12 +++--- src/ScriptCs/ScriptCs.csproj | 2 +- src/ScriptCs/ScriptServiceRoot.cs | 22 +++++++++++ 6 files changed, 94 insertions(+), 85 deletions(-) delete mode 100644 src/ScriptCs/Bootstrapper.cs create mode 100644 src/ScriptCs/ScriptServiceRoot.cs diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index 590a13eb..d2073f44 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,9 +1,18 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18010 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; using System.Reflection; -/** - * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the - * contents of 'build\ScriptCs.Version.props'. - **/ +[assembly: System.Reflection.AssemblyVersionAttribute("0.3.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("0.3.0-alpha")] + +// Generated by the MSBuild WriteCodeFragment class on 3/15/2013 1:13:26 PM. -[assembly: AssemblyVersion("0.0.0")] -[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file diff --git a/src/ScriptCs/Bootstrapper.cs b/src/ScriptCs/Bootstrapper.cs deleted file mode 100644 index d40b8c1c..00000000 --- a/src/ScriptCs/Bootstrapper.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.ComponentModel.Composition.Hosting; -using Autofac; -using Autofac.Integration.Mef; -using ScriptCs.Engine.Roslyn; -using ScriptCs.Package; - -namespace ScriptCs -{ - public class Bootstrapper - { - private readonly bool _debug; - private IContainer _container; - - public Bootstrapper(bool debug) - { - _debug = debug; - } - - public void Initialize() - { - var builder = new ContainerBuilder(); - var types = new[] - { - typeof (ScriptHostFactory), - typeof (FileSystem), - typeof (PackageAssemblyResolver), - typeof (PackageContainer), - typeof (FilePreProcessor), - typeof (ScriptPackResolver) - }; - - builder.RegisterTypes(types).AsImplementedInterfaces(); - - if (_debug) - { - builder.RegisterType().As(); - builder.RegisterType().As(); - } - else - { - builder.RegisterType().As(); - builder.RegisterType().As(); - } - - builder.RegisterType().As(); - - var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory, "*.pack.dll"); - builder.RegisterComposablePartCatalog(catalog); - _container = builder.Build(); - } - - public CompositionRoot GetCompositionRoot() - { - return _container.Resolve(); - } - } -} \ No newline at end of file diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 997cbf4a..9da6a0d9 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -1,22 +1,58 @@ -namespace ScriptCs +using System; +using System.ComponentModel.Composition.Hosting; +using Autofac; +using Autofac.Integration.Mef; +using ScriptCs.Engine.Roslyn; +using ScriptCs.Package; + +namespace ScriptCs { public class CompositionRoot { - public CompositionRoot( - IFileSystem fileSystem, - IPackageAssemblyResolver packageAssemblyResolver, - IScriptExecutor executor, - IScriptPackResolver scriptPackResolver ) + private readonly bool _debug; + private IContainer _container; + + public CompositionRoot(bool debug) { - FileSystem = fileSystem; - PackageAssemblyResolver = packageAssemblyResolver; - Executor = executor; - ScriptPackResolver = scriptPackResolver; + _debug = debug; } - public IFileSystem FileSystem { get; private set; } - public IPackageAssemblyResolver PackageAssemblyResolver { get; private set; } - public IScriptExecutor Executor { get; private set; } - public IScriptPackResolver ScriptPackResolver { get; private set; } + public void Initialize() + { + var builder = new ContainerBuilder(); + var types = new[] + { + typeof (ScriptHostFactory), + typeof (FileSystem), + typeof (PackageAssemblyResolver), + typeof (PackageContainer), + typeof (FilePreProcessor), + typeof (ScriptPackResolver) + }; + + builder.RegisterTypes(types).AsImplementedInterfaces(); + + if (_debug) + { + builder.RegisterType().As(); + builder.RegisterType().As(); + } + else + { + builder.RegisterType().As(); + builder.RegisterType().As(); + } + + builder.RegisterType().As(); + + var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory, "*.pack.dll"); + builder.RegisterComposablePartCatalog(catalog); + _container = builder.Build(); + } + + public ScriptServiceRoot GetServiceRoot() + { + return _container.Resolve(); + } } } \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 6d14a061..831f1351 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -20,20 +20,20 @@ private static void Main(string[] args) var script = commandArgs.ScriptName; var debug = commandArgs.DebugFlag; - var bootstrapper = new Bootstrapper(debug); - bootstrapper.Initialize(); - var root = bootstrapper.GetCompositionRoot(); + var compositionRoot = new CompositionRoot(debug); + compositionRoot.Initialize(); + var scriptServiceRoot = compositionRoot.GetServiceRoot(); try { - var workingDirectory = root.FileSystem.GetWorkingDirectory(script); - var paths = root.PackageAssemblyResolver.GetAssemblyNames(workingDirectory).ToList(); + var workingDirectory = scriptServiceRoot.FileSystem.GetWorkingDirectory(script); + var paths = scriptServiceRoot.PackageAssemblyResolver.GetAssemblyNames(workingDirectory).ToList(); foreach (var path in paths) { Console.WriteLine("Found assembly reference: " + path); } - root.Executor.Execute(script, paths, root.ScriptPackResolver.GetPacks()); + scriptServiceRoot.Executor.Execute(script, paths, scriptServiceRoot.ScriptPackResolver.GetPacks()); } catch (Exception ex) { diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index a99dadf7..9a2f8e4f 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -41,8 +41,8 @@ Properties\CommonVersionInfo.cs - + diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs new file mode 100644 index 00000000..a6d88173 --- /dev/null +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -0,0 +1,22 @@ +namespace ScriptCs +{ + public class ScriptServiceRoot + { + public ScriptServiceRoot( + IFileSystem fileSystem, + IPackageAssemblyResolver packageAssemblyResolver, + IScriptExecutor executor, + IScriptPackResolver scriptPackResolver ) + { + FileSystem = fileSystem; + PackageAssemblyResolver = packageAssemblyResolver; + Executor = executor; + ScriptPackResolver = scriptPackResolver; + } + + public IFileSystem FileSystem { get; private set; } + public IPackageAssemblyResolver PackageAssemblyResolver { get; private set; } + public IScriptExecutor Executor { get; private set; } + public IScriptPackResolver ScriptPackResolver { get; private set; } + } +} \ No newline at end of file From d58890ba8ab12ab80b773aead8e888072fdcd4be Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 15 Mar 2013 21:43:00 +0100 Subject: [PATCH 0120/1224] Added distinct to references and namespaces --- src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index daf36f9a..f95d7b4a 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -30,13 +30,10 @@ public void Execute(string code, IEnumerable references, ScriptPackSessi var session = _scriptEngine.CreateSession(host); - foreach (var reference in references) + foreach (var reference in references.Union(scriptPackSession.References).Distinct()) session.AddReference(reference); - foreach (var reference in scriptPackSession.References) - session.AddReference(reference); - - foreach (var @namespace in scriptPackSession.Namespaces) + foreach (var @namespace in scriptPackSession.Namespaces.Distinct()) session.ImportNamespace(@namespace); Execute(code, session); From 3b727fa29022408ab2e40b33766aadba4e2b9978 Mon Sep 17 00:00:00 2001 From: paul-sh Date: Sat, 16 Mar 2013 03:06:43 +0400 Subject: [PATCH 0121/1224] ScriptCs.exe returns an exit code, so ERRORLEVEL env. variable can be used to check result --- src/ScriptCs/Program.cs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 831f1351..b0f4b550 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -8,24 +8,24 @@ namespace ScriptCs { internal class Program { - private static void Main(string[] args) + private static int Main(string[] args) { - var commandArgs = Args.Parse(args); - - if (!commandArgs.IsValid()) - { - Console.WriteLine(ArgUsage.GetUsage()); - return; - } - - var script = commandArgs.ScriptName; - var debug = commandArgs.DebugFlag; - var compositionRoot = new CompositionRoot(debug); - compositionRoot.Initialize(); - var scriptServiceRoot = compositionRoot.GetServiceRoot(); - try { + var commandArgs = Args.Parse(args); + + if (!commandArgs.IsValid()) + { + Console.WriteLine(ArgUsage.GetUsage()); + return -1; + } + + var script = commandArgs.ScriptName; + var debug = commandArgs.DebugFlag; + var compositionRoot = new CompositionRoot(debug); + compositionRoot.Initialize(); + var scriptServiceRoot = compositionRoot.GetServiceRoot(); + var workingDirectory = scriptServiceRoot.FileSystem.GetWorkingDirectory(script); var paths = scriptServiceRoot.PackageAssemblyResolver.GetAssemblyNames(workingDirectory).ToList(); foreach (var path in paths) @@ -34,10 +34,12 @@ private static void Main(string[] args) } scriptServiceRoot.Executor.Execute(script, paths, scriptServiceRoot.ScriptPackResolver.GetPacks()); + return 0; } catch (Exception ex) { Console.WriteLine(ex.Message); + return -1; } } } From 8a70be4d5b208fad2bb3f0876bb3007b16d9d2ca Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 15 Mar 2013 21:17:03 -0400 Subject: [PATCH 0122/1224] added nuget -install and command factory --- src/ScriptCs.Core/Constants.cs | 1 + src/ScriptCs.Core/IPackageAssemblyResolver.cs | 7 +- .../Package/IPackageContainer.cs | 2 +- .../Package/IPackageInstaller.cs | 10 ++ src/ScriptCs.Core/Package/IPackageObject.cs | 7 +- .../Package/IPackageReference.cs | 3 + .../IInstallationProvider.cs | 11 ++ .../NugetInstallationProvider.cs | 68 ++++++++ src/ScriptCs.Core/Package/PackageContainer.cs | 41 ++++- src/ScriptCs.Core/Package/PackageInstaller.cs | 44 +++++ src/ScriptCs.Core/Package/PackageObject.cs | 26 ++- src/ScriptCs.Core/Package/PackageReference.cs | 6 +- src/ScriptCs.Core/PackageAssemblyResolver.cs | 80 +++++++-- src/ScriptCs.Core/ScriptCs.Core.csproj | 4 + src/ScriptCs/Command/CommandFactory.cs | 38 +++++ src/ScriptCs/Command/ICommand.cs | 19 +++ src/ScriptCs/Command/InstallCommand.cs | 42 +++++ src/ScriptCs/Command/InvalidCommand.cs | 12 ++ src/ScriptCs/Command/ScriptExecuteCommand.cs | 44 +++++ src/ScriptCs/Program.cs | 28 +--- src/ScriptCs/ScriptCs.csproj | 5 + src/ScriptCs/ScriptCsArgs.cs | 8 +- .../PackageAssemblyResolverTests.cs | 155 ++++++++++++++++-- .../PackageInstallerTests.cs | 95 +++++++++++ .../ScriptCs.Core.Tests.csproj | 1 + test/ScriptCs.Tests/CommandFactoryTests.cs | 106 ++++++++++++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 12 ++ 27 files changed, 812 insertions(+), 63 deletions(-) create mode 100644 src/ScriptCs.Core/Package/IPackageInstaller.cs create mode 100644 src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs create mode 100644 src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs create mode 100644 src/ScriptCs.Core/Package/PackageInstaller.cs create mode 100644 src/ScriptCs/Command/CommandFactory.cs create mode 100644 src/ScriptCs/Command/ICommand.cs create mode 100644 src/ScriptCs/Command/InstallCommand.cs create mode 100644 src/ScriptCs/Command/InvalidCommand.cs create mode 100644 src/ScriptCs/Command/ScriptExecuteCommand.cs create mode 100644 test/ScriptCs.Core.Tests/PackageInstallerTests.cs create mode 100644 test/ScriptCs.Tests/CommandFactoryTests.cs diff --git a/src/ScriptCs.Core/Constants.cs b/src/ScriptCs.Core/Constants.cs index 28bb1585..8a78a48f 100644 --- a/src/ScriptCs.Core/Constants.cs +++ b/src/ScriptCs.Core/Constants.cs @@ -4,6 +4,7 @@ public static class Constants { public const string PackagesFile = "packages.config"; public const string PackagesFolder = "packages"; + public const string DefaultRepositoryUrl = "https://nuget.org/api/v2/"; public const string DebugContractName = "Debug"; public const string RunContractName = "Run"; diff --git a/src/ScriptCs.Core/IPackageAssemblyResolver.cs b/src/ScriptCs.Core/IPackageAssemblyResolver.cs index 20e81578..2c927dab 100644 --- a/src/ScriptCs.Core/IPackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/IPackageAssemblyResolver.cs @@ -1,9 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using ScriptCs.Package; namespace ScriptCs { public interface IPackageAssemblyResolver { - IEnumerable GetAssemblyNames(string workingDirectory); + IEnumerable GetPackages(string workingDirectory); + IEnumerable GetAssemblyNames(string workingDirectory, Action outputCallback = null); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/IPackageContainer.cs b/src/ScriptCs.Core/Package/IPackageContainer.cs index 56f3f673..2866e49b 100644 --- a/src/ScriptCs.Core/Package/IPackageContainer.cs +++ b/src/ScriptCs.Core/Package/IPackageContainer.cs @@ -5,6 +5,6 @@ namespace ScriptCs.Package public interface IPackageContainer { IEnumerable FindReferences(string path); - IPackageObject FindPackage(string path, string packageId); + IPackageObject FindPackage(string path, IPackageReference packageReference); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/IPackageInstaller.cs b/src/ScriptCs.Core/Package/IPackageInstaller.cs new file mode 100644 index 00000000..3fc1ea42 --- /dev/null +++ b/src/ScriptCs.Core/Package/IPackageInstaller.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace ScriptCs.Package +{ + public interface IPackageInstaller + { + void InstallPackages(IEnumerable packageIds, bool allowPreRelease = false, Action packageInstalled = null); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/IPackageObject.cs b/src/ScriptCs.Core/Package/IPackageObject.cs index 838885bf..2305baac 100644 --- a/src/ScriptCs.Core/Package/IPackageObject.cs +++ b/src/ScriptCs.Core/Package/IPackageObject.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Runtime.Versioning; @@ -6,8 +7,12 @@ namespace ScriptCs.Package public interface IPackageObject { string Id { get; } - string Version { get; } + string TextVersion { get; } + Version Version { get; } string FullName { get; } IEnumerable GetCompatibleDlls(FrameworkName frameworkName); + FrameworkName FrameworkName { get; } + + IEnumerable Dependencies { get; } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/IPackageReference.cs b/src/ScriptCs.Core/Package/IPackageReference.cs index 57810d66..20b93541 100644 --- a/src/ScriptCs.Core/Package/IPackageReference.cs +++ b/src/ScriptCs.Core/Package/IPackageReference.cs @@ -1,3 +1,4 @@ +using System; using System.Runtime.Versioning; namespace ScriptCs.Package @@ -6,5 +7,7 @@ public interface IPackageReference { string PackageId { get; } FrameworkName FrameworkName { get; } + Version Version { get; set; } + string SpecialVersion { get; } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs new file mode 100644 index 00000000..525de7f9 --- /dev/null +++ b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace ScriptCs.Package.InstallationProvider +{ + public interface IInstallationProvider + { + IEnumerable GetRepositorySources(string path); + bool InstallPackage(IPackageReference packageId, bool allowPreRelease = false, Action packageInstalled = null); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs new file mode 100644 index 00000000..1c4cb758 --- /dev/null +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using NuGet; + +namespace ScriptCs.Package.InstallationProvider +{ + internal class NugetInstallationProvider : IInstallationProvider + { + private readonly PackageManager _manager; + private readonly IEnumerable _repositoryUrls; + + public NugetInstallationProvider(IFileSystem fileSystem) + { + var path = Path.Combine(fileSystem.CurrentDirectory, Constants.PackagesFolder); + _repositoryUrls = GetRepositorySources(path); + var remoteRepository = new AggregateRepository(PackageRepositoryFactory.Default, _repositoryUrls, true); + _manager = new PackageManager(remoteRepository, path); + } + + public IEnumerable GetRepositorySources(string path) + { + var configFileSystem = new PhysicalFileSystem(path); + var settings = Settings.LoadDefaultSettings(configFileSystem); + if (settings == null) return new[] { Constants.DefaultRepositoryUrl }; + + var sourceProvider = new PackageSourceProvider(settings); + var sources = sourceProvider.LoadPackageSources(); + + if (sources == null || !sources.Any()) return new[] { Constants.DefaultRepositoryUrl }; + + return sources.Select(i => i.Source); + } + + public bool InstallPackage(IPackageReference packageId, bool allowPreRelease = false, Action packageInstalled = null) + { + var useVersion = packageId.Version.CompareTo(new Version()) != 0; + try + { + if (useVersion) + { + _manager.InstallPackage(packageId.PackageId, + new SemanticVersion(packageId.Version, packageId.SpecialVersion), false, + allowPreRelease); + } + else + { + _manager.InstallPackage(packageId.PackageId); + } + + if (packageInstalled != null) + packageInstalled("Installed: " + packageId.PackageId + " " + (useVersion ? packageId.Version.ToString() : "")); + + return true; + } + catch (Exception e) + { + if (packageInstalled != null) + { + packageInstalled("Installation failed: " + packageId.PackageId + " " + (useVersion ? packageId.Version.ToString() : "")); + packageInstalled(e.Message); + } + return false; + } + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index 91b939e0..9ad624e7 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using NuGet; @@ -6,21 +7,51 @@ namespace ScriptCs.Package { internal class PackageContainer : IPackageContainer { - public IPackageObject FindPackage(string path, string packageId) + private readonly IFileSystem _fileSystem; + + public PackageContainer(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + + public IPackageObject FindPackage(string path, IPackageReference packageRef) { var repository = new LocalPackageRepository(path); + IPackage package; + if (packageRef.Version != null) + { + package = repository.FindPackage(packageRef.PackageId, new SemanticVersion(packageRef.Version, packageRef.SpecialVersion), true, true); + } + else + { + package = repository.FindPackage(packageRef.PackageId); + } - var package = repository.FindPackage(packageId); - return package == null ? null : new PackageObject(package); + return package == null ? null : new PackageObject(package, packageRef.FrameworkName); } public IEnumerable FindReferences(string path) { var packageReferenceFile = new PackageReferenceFile(path); var references = packageReferenceFile.GetPackageReferences(); - if (references == null) return Enumerable.Empty(); - var packages = references.Select(i => new PackageReference(i.Id, i.TargetFramework)); + if (!references.Any()) + { + var packagesFolder = Path.Combine(_fileSystem.GetWorkingDirectory(path), Constants.PackagesFolder); + if (_fileSystem.DirectoryExists(packagesFolder)) + { + var repository = new LocalPackageRepository(packagesFolder); + var arbitraryPackages = repository.GetPackages().Where(i => i.GetSupportedFrameworks().Any(x => x.FullName == VersionUtility.ParseFrameworkName("net40").FullName)).ToList(); + if (arbitraryPackages.Any()) + { + return arbitraryPackages.Select(i => new PackageReference(i.Id, VersionUtility.ParseFrameworkName("net40"), i.Version.Version) { SpecialVersion = i.Version.SpecialVersion }); + } + } + + return Enumerable.Empty(); + } + + var packages = references.Select(i => new PackageReference(i.Id, i.TargetFramework, i.Version.Version) { SpecialVersion = i.Version.SpecialVersion }); return packages; } } diff --git a/src/ScriptCs.Core/Package/PackageInstaller.cs b/src/ScriptCs.Core/Package/PackageInstaller.cs new file mode 100644 index 00000000..a7e842a2 --- /dev/null +++ b/src/ScriptCs.Core/Package/PackageInstaller.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs.Package +{ + public class PackageInstaller : IPackageInstaller + { + private readonly IInstallationProvider _installer; + + public PackageInstaller(IInstallationProvider installer) + { + _installer = installer; + } + + public void InstallPackages(IEnumerable packageIds, bool allowPreRelease = false, Action packageInstalled = null) + { + if (packageIds == null) throw new ArgumentNullException("packageIds"); + packageIds = packageIds.ToList(); + + if (!packageIds.Any()) + { + if (packageInstalled != null) + { + packageInstalled("Nothing to install."); + } + return; + } + + var successful = true; + foreach (var packageId in packageIds) + { + var result = _installer.InstallPackage(packageId, allowPreRelease, packageInstalled); + successful = successful && result; + } + + if (packageInstalled != null && packageIds.Count() > 1) + { + packageInstalled(successful ? "Installation successful" : "Installation unsuccessful"); + } + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/PackageObject.cs b/src/ScriptCs.Core/Package/PackageObject.cs index 5d68e40a..7c8167d5 100644 --- a/src/ScriptCs.Core/Package/PackageObject.cs +++ b/src/ScriptCs.Core/Package/PackageObject.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Versioning; @@ -10,19 +11,36 @@ internal class PackageObject : IPackageObject private const string Dll = ".dll"; private readonly IPackage _package; - public PackageObject(IPackage package) + public PackageObject(IPackage package, FrameworkName frameworkName) { _package = package; + FrameworkName = frameworkName; Id = package.Id; - Version = package.Version.ToString(); + Version = package.Version.Version; + TextVersion = package.Version.ToString(); + + var dependencies = _package.GetCompatiblePackageDependencies(frameworkName); + if (dependencies != null) + { + Dependencies = dependencies.Select(i => new PackageObject(i.Id) {FrameworkName = frameworkName}); + } + } + + public PackageObject(string packageId) + { + Id = packageId; } public string Id { get; private set; } - public string Version { get; private set; } + public string TextVersion { get; private set; } + public Version Version { get; private set; } + public FrameworkName FrameworkName { get; private set; } + + public IEnumerable Dependencies { get; set; } public string FullName { - get { return Id + "." + Version; } + get { return Id + "." + TextVersion; } } public IEnumerable GetCompatibleDlls(FrameworkName frameworkName) diff --git a/src/ScriptCs.Core/Package/PackageReference.cs b/src/ScriptCs.Core/Package/PackageReference.cs index f8a0952d..a24fb4c4 100644 --- a/src/ScriptCs.Core/Package/PackageReference.cs +++ b/src/ScriptCs.Core/Package/PackageReference.cs @@ -1,16 +1,20 @@ +using System; using System.Runtime.Versioning; namespace ScriptCs.Package { public class PackageReference : IPackageReference { - public PackageReference(string packageId, FrameworkName frameworkName) + public PackageReference(string packageId, FrameworkName frameworkName, Version version) { FrameworkName = frameworkName; PackageId = packageId; + Version = version; } public string PackageId { get; private set; } public FrameworkName FrameworkName { get; private set; } + public Version Version { get; set; } + public string SpecialVersion { get; set; } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/PackageAssemblyResolver.cs b/src/ScriptCs.Core/PackageAssemblyResolver.cs index 9fd05a4d..f2279ac7 100644 --- a/src/ScriptCs.Core/PackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/PackageAssemblyResolver.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using ScriptCs.Exceptions; @@ -10,6 +11,7 @@ public class PackageAssemblyResolver : IPackageAssemblyResolver { private readonly IFileSystem _fileSystem; private readonly IPackageContainer _packageContainer; + private IEnumerable _topLevelPackages; public PackageAssemblyResolver(IFileSystem fileSystem, IPackageContainer packageContainer) { @@ -17,43 +19,85 @@ public PackageAssemblyResolver(IFileSystem fileSystem, IPackageContainer package _packageContainer = packageContainer; } - public IEnumerable GetAssemblyNames(string workingDirectory) + public IEnumerable GetPackages(string workingDirectory) { - var packageDir = Path.Combine(workingDirectory, Constants.PackagesFolder); - var packageFilePath = Path.Combine(workingDirectory, Constants.PackagesFile); - if (!_fileSystem.DirectoryExists(packageDir) || !_fileSystem.FileExists(packageFilePath)) + var packageFile = Path.Combine(workingDirectory, Constants.PackagesFile); + var packages = _packageContainer.FindReferences(packageFile); + _topLevelPackages = packages; + + return packages; + } + + public IEnumerable GetAssemblyNames(string workingDirectory, Action outputCallback = null) + { + var packages = GetPackages(workingDirectory); + if (!packages.Any()) + { return Enumerable.Empty(); + } + + var packageFile = Path.Combine(workingDirectory, Constants.PackagesFile); + var packageDir = Path.Combine(workingDirectory, Constants.PackagesFolder); - var packages = _packageContainer.FindReferences(packageFilePath); var foundAssemblyPaths = new List(); var missingAssemblies = new List(); - foreach (var package in packages) + LoadFiles(packageDir, packages, ref missingAssemblies, ref foundAssemblyPaths, _fileSystem.FileExists(packageFile), outputCallback); + + if (missingAssemblies.Count > 0) + throw new MissingAssemblyException(string.Format("Missing: {0}", string.Join(",", missingAssemblies.Select(i => i.PackageId + " " + i.FrameworkName.FullName)))); + + return foundAssemblyPaths; + } + + private void LoadFiles(string packageDir, IEnumerable packageReferences, ref List missingAssemblies, ref List foundAssemblies, bool strictLoad = true, Action outputCallback = null) + { + foreach (var packageRef in packageReferences) { - var nugetPackage = _packageContainer.FindPackage(packageDir, package.PackageId); + var nugetPackage = _packageContainer.FindPackage(packageDir, packageRef); if (nugetPackage == null) { - missingAssemblies.Add(package); + missingAssemblies.Add(packageRef); + if (outputCallback != null) + { + outputCallback("Cannot find: " + packageRef.PackageId + " " + packageRef.Version); + } continue; } - var compatibleFiles = nugetPackage.GetCompatibleDlls(package.FrameworkName); + var compatibleFiles = nugetPackage.GetCompatibleDlls(packageRef.FrameworkName); if (compatibleFiles == null) { - missingAssemblies.Add(package); + missingAssemblies.Add(packageRef); + if (outputCallback != null) + { + outputCallback("Cannot find binaries for " + packageRef.FrameworkName + " in: " + + packageRef.PackageId + " " + packageRef.Version); + } continue; } - foreach (var packageFile in compatibleFiles) { + foreach (var packageFile in compatibleFiles) + { var path = Path.Combine(packageDir, nugetPackage.FullName, packageFile); - foundAssemblyPaths.Add(path); + if (!foundAssemblies.Contains(path)) + { + foundAssemblies.Add(path); + if (outputCallback != null) + { + outputCallback("Found: " + path); + } + } } - } - if (missingAssemblies.Count > 0) - throw new MissingAssemblyException(string.Format("Missing: {0}", string.Join(",", missingAssemblies.Select(i => i.PackageId + " " + i.FrameworkName.FullName)))); - - return foundAssemblyPaths; + if (nugetPackage.Dependencies != null && nugetPackage.Dependencies.Any() && strictLoad) + { + LoadFiles(packageDir, + nugetPackage.Dependencies.Where(i => _topLevelPackages.All(x => x.PackageId != i.Id)).Select( + i => new PackageReference(i.Id, i.FrameworkName, i.Version)), ref missingAssemblies, + ref foundAssemblies, true, outputCallback); + } + } } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index aead005c..a0156d02 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -42,7 +42,11 @@ + + + + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs new file mode 100644 index 00000000..b185354e --- /dev/null +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -0,0 +1,38 @@ +using System.ComponentModel.Composition.Hosting; +using ScriptCs.Package; + +namespace ScriptCs.Command +{ + public class CommandFactory + { + private readonly ExportProvider _exportProvider; + + public CommandFactory(ExportProvider exportProvider) + { + _exportProvider = exportProvider; + } + + public ICommand CreateCommand(ScriptCsArgs args) + { + if (args.ScriptName != null) + { + var fileSystem = _exportProvider.GetExportedValue(); + var resolver = _exportProvider.GetExportedValue(); + var scriptExecutor = _exportProvider.GetExportedValue(); + var scriptPackManager = new ScriptPackResolver(_exportProvider); + return new ScriptExecuteCommand(args.ScriptName, fileSystem, resolver, scriptExecutor, scriptPackManager); + } + + if (args.Install != null) + { + var fileSystem = _exportProvider.GetExportedValue(); + var resolver = _exportProvider.GetExportedValue(); + var packageInstaller = _exportProvider.GetExportedValue(); + + return new InstallCommand(args.Install, args.AllowPreReleaseFlag, fileSystem, resolver, packageInstaller); + } + + return new InvalidCommand(); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs new file mode 100644 index 00000000..4a039a0c --- /dev/null +++ b/src/ScriptCs/Command/ICommand.cs @@ -0,0 +1,19 @@ +namespace ScriptCs.Command +{ + public interface IScriptCommand : ICommand + { + } + + public interface IInstallCommand : ICommand + { + } + + public interface IInvalidCommand : ICommand + { + } + + public interface ICommand + { + void Execute(); + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs new file mode 100644 index 00000000..e63b775e --- /dev/null +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Versioning; +using ScriptCs.Package; + +namespace ScriptCs.Command +{ + internal class InstallCommand : IInstallCommand + { + private readonly string _name; + private readonly bool _allowPre; + private readonly IFileSystem _fileSystem; + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + private readonly IPackageInstaller _packageInstaller; + + public InstallCommand(string name, bool allowPre, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IPackageInstaller packageInstaller) + { + _name = name; + _allowPre = allowPre; + _fileSystem = fileSystem; + _packageAssemblyResolver = packageAssemblyResolver; + _packageInstaller = packageInstaller; + } + + public void Execute() + { + var workingDirectory = _fileSystem.CurrentDirectory; + IEnumerable pkgs; + + if (string.IsNullOrWhiteSpace(_name)) + { + pkgs = _packageAssemblyResolver.GetPackages(workingDirectory); + } + else + { + pkgs = new[] { new PackageReference(_name, new FrameworkName(".NETFramework,Version=v4.0"), new Version()) }; + } + _packageInstaller.InstallPackages(pkgs, _allowPre, msg => Console.WriteLine(msg)); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/InvalidCommand.cs b/src/ScriptCs/Command/InvalidCommand.cs new file mode 100644 index 00000000..31bb8ba0 --- /dev/null +++ b/src/ScriptCs/Command/InvalidCommand.cs @@ -0,0 +1,12 @@ +using System; + +namespace ScriptCs.Command +{ + internal class InvalidCommand : IInvalidCommand + { + public void Execute() + { + Console.WriteLine("Invalid use!"); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/ScriptExecuteCommand.cs b/src/ScriptCs/Command/ScriptExecuteCommand.cs new file mode 100644 index 00000000..6712f8b6 --- /dev/null +++ b/src/ScriptCs/Command/ScriptExecuteCommand.cs @@ -0,0 +1,44 @@ +using System; +using System.ComponentModel.Composition.Hosting; +using System.Linq; +using ScriptCs.Exceptions; + +namespace ScriptCs.Command +{ + internal class ScriptExecuteCommand : IScriptCommand + { + private readonly string _script; + private readonly IFileSystem _fileSystem; + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + private readonly IScriptExecutor _scriptExecutor; + private readonly ScriptPackResolver _scriptPackResolver; + + public ScriptExecuteCommand(string script, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IScriptExecutor scriptExecutor, ScriptPackResolver scriptPackResolver) + { + _script = script; + _fileSystem = fileSystem; + _packageAssemblyResolver = packageAssemblyResolver; + _scriptExecutor = scriptExecutor; + _scriptPackResolver = scriptPackResolver; + } + + public void Execute() + { + try + { + var workingDirectory = _fileSystem.GetWorkingDirectory(_script); + var paths = _packageAssemblyResolver.GetAssemblyNames(workingDirectory).ToList(); + foreach (var path in paths) + { + Console.WriteLine("Found assembly reference: " + path); + } + + _scriptExecutor.Execute(_script, paths, _scriptPackResolver.GetPacks()); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 61c51b6e..6e14a09b 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,11 +1,14 @@ using System; +using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Linq; using PowerArgs; +using ScriptCs.Command; using ScriptCs.Engine.Roslyn; using System.ComponentModel.Composition.Registration; using ScriptCs.Contracts; using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; namespace ScriptCs { @@ -21,30 +24,13 @@ private static void Main(string[] args) return; } - var script = commandArgs.ScriptName; var debug = commandArgs.DebugFlag; var container = ConfigureMef(debug); - var fileSystem = container.GetExportedValue(); - var resolver = container.GetExportedValue(); - var executor = container.GetExportedValue(); - var scriptPackManager = new ScriptPackResolver(container); + var commandFactory = new CommandFactory(container); + var command = commandFactory.CreateCommand(commandArgs); - try - { - var workingDirectory = fileSystem.GetWorkingDirectory(script); - var paths = resolver.GetAssemblyNames(workingDirectory).ToList(); - foreach (var path in paths) - { - Console.WriteLine("Found assembly reference: " + path); - } - - executor.Execute(script, paths, scriptPackManager.GetPacks()); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } + command.Execute(); } private static CompositionContainer ConfigureMef(bool debug) @@ -69,6 +55,8 @@ private static RegistrationBuilder SetupMefConventions(bool debug) conventions.ForTypesDerivedFrom().Export(); conventions.ForTypesDerivedFrom().Export(); conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); if (debug) { diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 522477a9..cfbebea4 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -33,6 +33,11 @@ Properties\CommonVersionInfo.cs + + + + + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 910d12a1..5b7fe5fb 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -12,9 +12,15 @@ public class ScriptCsArgs [ArgShortcut("debug")] public bool DebugFlag { get; set; } + [ArgShortcut("install")] + public string Install { get; set; } + + [ArgShortcut("pre")] + public bool AllowPreReleaseFlag { get; set; } + public bool IsValid() { - return !string.IsNullOrWhiteSpace(ScriptName); + return !string.IsNullOrWhiteSpace(ScriptName) || Install != null; } } } \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/PackageAssemblyResolverTests.cs b/test/ScriptCs.Core.Tests/PackageAssemblyResolverTests.cs index 51a57be3..6c624640 100644 --- a/test/ScriptCs.Core.Tests/PackageAssemblyResolverTests.cs +++ b/test/ScriptCs.Core.Tests/PackageAssemblyResolverTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Runtime.Versioning; using ScriptCs.Exceptions; @@ -34,23 +35,25 @@ public GetAssemblyNamesMethod() _package.Setup(i => i.GetCompatibleDlls(It.IsAny())) .Returns(new List {"test.dll", "test2.dll"}); _package.SetupGet(i => i.Id).Returns("id"); - _package.SetupGet(i => i.Version).Returns("3.0"); + _package.SetupGet(i => i.Version).Returns(new Version("3.0")); + _package.SetupGet(i => i.TextVersion).Returns("3.0"); _package.SetupGet(i => i.FullName).Returns(_package.Object.Id + "." + _package.Object.Version); _packageIds = new List { - new PackageReference("testId", VersionUtility.ParseFrameworkName("net40")) + new PackageReference("testId", VersionUtility.ParseFrameworkName("net40"), new Version("3.0")) }; _packageContainer = new Mock(); _packageContainer.Setup(i => i.FindReferences(It.IsAny())).Returns(_packageIds); - _packageContainer.Setup(i => i.FindPackage(It.IsAny(), It.IsAny())).Returns(_package.Object); + _packageContainer.Setup(i => i.FindPackage(It.IsAny(), It.IsAny())).Returns(_package.Object); } [Fact] - public void WhenPackageIsMatchedItsMatchingDllsShouldBeReturned() + public void WhenManyPackagesAreMatchedAllMatchingDllsWithUniquePathsShouldBeReturned() { var resolver = new PackageAssemblyResolver(_filesystem.Object, _packageContainer.Object); + _packageIds.Add(new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"), new Version("3.0"))); var found = resolver.GetAssemblyNames(_workingDirectory).ToList(); @@ -61,9 +64,18 @@ public void WhenPackageIsMatchedItsMatchingDllsShouldBeReturned() [Fact] public void WhenManyPackagesAreMatchedAllMatchingDllsShouldBeReturned() { - var resolver = new PackageAssemblyResolver(_filesystem.Object, _packageContainer.Object); - _packageIds.Add(new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"))); + _packageIds.Add(new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"), new Version("3.0"))); + var p = new Mock(); + p.Setup(i => i.GetCompatibleDlls(It.IsAny())) + .Returns(new List { "test3.dll", "test4.dll" }); + p.SetupGet(i => i.Id).Returns("testId2"); + p.SetupGet(i => i.Version).Returns(new Version("3.0")); + p.SetupGet(i => i.TextVersion).Returns("3.0"); + p.SetupGet(i => i.FullName).Returns(_package.Object.Id + "." + _package.Object.Version); + + _packageContainer.Setup(i => i.FindPackage(It.IsAny(), It.Is(x => x.PackageId == "testId2"))).Returns(p.Object); + var resolver = new PackageAssemblyResolver(_filesystem.Object, _packageContainer.Object); var found = resolver.GetAssemblyNames(_workingDirectory).ToList(); found.ShouldNotBeEmpty(); @@ -94,8 +106,18 @@ public void WhenManyPackagesAreMatchedAllNonMatchingDllsShouldBeExcluded() i => i.GetCompatibleDlls( It.Is(x => x.FullName == VersionUtility.ParseFrameworkName("net40").FullName))) - .Returns(new List {"test.dll"}); - _packageIds.Add(new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"))); + .Returns(new List { "test.dll" }); + _packageIds.Add(new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"), new Version("3.0"))); + + var p = new Mock(); + p.Setup(i => i.GetCompatibleDlls(It.IsAny())) + .Returns(new List { "test3.dll" }); + p.SetupGet(i => i.Id).Returns("testId2"); + p.SetupGet(i => i.Version).Returns(new Version("3.0")); + p.SetupGet(i => i.TextVersion).Returns("3.0"); + p.SetupGet(i => i.FullName).Returns(_package.Object.Id + "." + _package.Object.Version); + + _packageContainer.Setup(i => i.FindPackage(It.IsAny(), It.Is(x => x.PackageId == "testId2"))).Returns(p.Object); var resolver = new PackageAssemblyResolver(_filesystem.Object, _packageContainer.Object); @@ -119,7 +141,7 @@ public void WhenDllsAreMatchedDllFilePathsAreCorrectlyConcatenated() [Fact] public void WhenNoPackagesAreFoundShouldThrowArgumentEx() { - _packageContainer.Setup(i => i.FindPackage(It.IsAny(), It.IsAny())) + _packageContainer.Setup(i => i.FindPackage(It.IsAny(), It.IsAny())) .Returns>(null); var resolver = new PackageAssemblyResolver(_filesystem.Object, _packageContainer.Object); @@ -156,6 +178,119 @@ public void WhenPackagesConfigDoesNotExistShouldReturnEmptyPackagesList() var found = resolver.GetAssemblyNames(_workingDirectory); found.ShouldBeEmpty(); } + + [Fact] + public void ShouldLoadAllDependenciesIfPackageHasAny() + { + var p = new Mock(); + p.Setup(i => i.GetCompatibleDlls(It.IsAny())) + .Returns(new List { "test3.dll", "test4.dll" }); + p.SetupGet(i => i.Id).Returns("p2"); + p.SetupGet(i => i.Version).Returns(new Version("4.0")); + p.SetupGet(i => i.TextVersion).Returns("4.0"); + p.SetupGet(i => i.FullName).Returns(_package.Object.Id + "." + _package.Object.Version); + + _package.Setup(i => i.Dependencies).Returns(new List { p.Object }); + _packageContainer.Setup( + i => i.FindPackage(It.IsAny(), It.Is(x => x.PackageId == "p2"))) + .Returns(p.Object); + + var resolver = new PackageAssemblyResolver(_filesystem.Object, _packageContainer.Object); + + var found = resolver.GetAssemblyNames(_workingDirectory).ToList(); + + _packageContainer.Verify(i => i.FindPackage(It.IsAny(), It.IsAny()), Times.Exactly(2)); + found.ShouldNotBeEmpty(); + found.Count.ShouldEqual(4); + } + + [Fact] + public void ShouldNotLoadDuplicateDependencies() + { + var p = new Mock(); + p.Setup(i => i.GetCompatibleDlls(It.IsAny())) + .Returns(new List { "test3.dll", "test4.dll" }); + p.SetupGet(i => i.Id).Returns("p2"); + p.SetupGet(i => i.Version).Returns(new Version("4.0")); + p.SetupGet(i => i.TextVersion).Returns("4.0"); + p.SetupGet(i => i.FullName).Returns(_package.Object.Id + "." + _package.Object.Version); + + _packageIds.Add(new PackageReference("p2", VersionUtility.ParseFrameworkName("net40"), new Version("3.0"))); + + _package.Setup(i => i.Dependencies).Returns(new List { p.Object }); + _packageContainer.Setup( + i => i.FindPackage(It.IsAny(), It.Is(x => x.PackageId == "p2"))) + .Returns(p.Object); + + var resolver = new PackageAssemblyResolver(_filesystem.Object, _packageContainer.Object); + + var found = resolver.GetAssemblyNames(_workingDirectory).ToList(); + + _packageContainer.Verify(i => i.FindPackage(It.IsAny(), It.IsAny()), Times.Exactly(2)); + found.ShouldNotBeEmpty(); + found.Count.ShouldEqual(4); + } + + [Fact] + public void ShouldNotLoadIncompatibleDependenciesDlls() + { + var p = new Mock(); + p.Setup(i => i.GetCompatibleDlls(It.IsAny())) + .Returns(new List()); + p.SetupGet(i => i.Id).Returns("p2"); + p.SetupGet(i => i.Version).Returns(new Version("4.0")); + p.SetupGet(i => i.TextVersion).Returns("4.0"); + p.SetupGet(i => i.FullName).Returns(_package.Object.Id + "." + _package.Object.Version); + + _package.Setup(i => i.Dependencies).Returns(new List { p.Object }); + _packageContainer.Setup( + i => i.FindPackage(It.IsAny(), It.Is(x => x.PackageId == "p2"))) + .Returns(p.Object); + + var resolver = new PackageAssemblyResolver(_filesystem.Object, _packageContainer.Object); + + var found = resolver.GetAssemblyNames(_workingDirectory).ToList(); + + _packageContainer.Verify(i => i.FindPackage(It.IsAny(), It.IsAny()), Times.Exactly(2)); + found.ShouldNotBeEmpty(); + found.Count.ShouldEqual(2); + } + } + + public class GetPackagesMethod + { + private Mock _fs; + private Mock _pc; + + public GetPackagesMethod() + { + _fs = new Mock(); + _pc = new Mock(); + } + + [Fact] + public void ShouldReturnEmptyIfPackagesConfigDoesNotExist() + { + _fs.Setup(i => i.FileExists(It.IsAny())).Returns(false); + + var resolver = new PackageAssemblyResolver(_fs.Object, _pc.Object); + var result = resolver.GetPackages(@"c:/"); + + result.ShouldBeEmpty(); + } + + [Fact] + public void ShouldGetReferencesToPackages() + { + _fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); + _pc.Setup(i => i.FindReferences(It.IsAny())).Returns(new List { new PackageReference("id", VersionUtility.ParseFrameworkName("net40"), new Version("3.0")) }); + + var resolver = new PackageAssemblyResolver(_fs.Object, _pc.Object); + var result = resolver.GetPackages(@"c:/"); + + _pc.Verify(i => i.FindReferences(It.IsAny()), Times.Once()); + result.Count().ShouldEqual(1); + } } } } diff --git a/test/ScriptCs.Core.Tests/PackageInstallerTests.cs b/test/ScriptCs.Core.Tests/PackageInstallerTests.cs new file mode 100644 index 00000000..d3739c22 --- /dev/null +++ b/test/ScriptCs.Core.Tests/PackageInstallerTests.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; +using NuGet; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; +using Should; +using Xunit; +using PackageReference = ScriptCs.Package.PackageReference; + +namespace ScriptCs.Tests +{ + public class PackageInstallerTests + { + public class InstallPackagesMethod + { + [Fact] + public void ShouldThrowArgumentNullExWhenNoPackageIdsPassed() + { + var installer = new PackageInstaller(new Mock().Object); + + Assert.Throws(() => installer.InstallPackages(null)); + } + + [Fact] + public void ShouldInstallAllPassedPackages() + { + var provider = new Mock(); + provider.Setup( + i => i.InstallPackage(It.IsAny(), It.IsAny(), It.IsAny>())) + .Returns(true); + + var references = new List { + new PackageReference("testId", VersionUtility.ParseFrameworkName("net40"), new Version("3.0")), + new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"), new Version("4.0")), + new PackageReference("testId3", VersionUtility.ParseFrameworkName("net40"), new Version("5.0")) + }; + + var installer = new PackageInstaller(provider.Object); + installer.InstallPackages(references); + + provider.Verify(i => i.InstallPackage(It.IsAny(), It.IsAny(), It.IsAny>()), Times.Exactly(3)); + } + + [Fact] + public void ShouldShowErrorIfOneOfPackagesFail() + { + var callbacks = new List(); + var provider = new Mock(); + provider.Setup( + i => i.InstallPackage(It.IsAny(), It.IsAny(), It.IsAny>())) + .Returns(true); + provider.Setup( + i => i.InstallPackage(It.Is(x => x.PackageId == "testId"), It.IsAny(), It.IsAny>())) + .Returns(false); + + var references = new List { + new PackageReference("testId", VersionUtility.ParseFrameworkName("net40"), new Version("3.0")), + new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"), new Version("4.0")), + new PackageReference("testId3", VersionUtility.ParseFrameworkName("net40"), new Version("5.0")) + }; + + var installer = new PackageInstaller(provider.Object); + installer.InstallPackages(references, true, msg => callbacks.Add(msg)); + + provider.Verify(i => i.InstallPackage(It.IsAny(), It.IsAny(), It.IsAny>()), Times.Exactly(3)); + callbacks.Count.ShouldEqual(1); + callbacks.Count(x => x.EndsWith("unsuccessful")).ShouldEqual(1); + } + + [Fact] + public void ShouldShowSuccessIfNoneOfPackagesFail() + { + var callbacks = new List(); + var provider = new Mock(); + provider.Setup( + i => i.InstallPackage(It.IsAny(), It.IsAny(), It.IsAny>())) + .Returns(true); + + var references = new List { + new PackageReference("testId", VersionUtility.ParseFrameworkName("net40"), new Version("3.0")), + new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"), new Version("4.0")), + new PackageReference("testId3", VersionUtility.ParseFrameworkName("net40"), new Version("5.0")) + }; + + var installer = new PackageInstaller(provider.Object); + installer.InstallPackages(references, true, msg => callbacks.Add(msg)); + + callbacks.Count.ShouldEqual(1); + callbacks.Count(x => x.EndsWith("successful")).ShouldEqual(1); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 7ac4d681..f8d7a25e 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -35,6 +35,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs new file mode 100644 index 00000000..27d67a5c --- /dev/null +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -0,0 +1,106 @@ +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Registration; +using ScriptCs.Command; +using ScriptCs.Engine.Roslyn; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class CommandFactoryTests + { + public class CreateCommandMethod + { + private static CompositionContainer CreateCompositionContainer() + { + var conventions = new RegistrationBuilder(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForTypesDerivedFrom().Export(); + conventions.ForType().Export(); + conventions.ForType().Export(); + + var catalog = new AggregateCatalog(); + catalog.Catalogs.Add(new AssemblyCatalog(typeof(ScriptExecutor).Assembly, conventions)); + catalog.Catalogs.Add(new AssemblyCatalog(typeof(RoslynScriptEngine).Assembly, conventions)); + + var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection); + + return container; + } + + [Fact] + public void ShouldInstallWhenInstallFlagIsOn() + { + var args = new ScriptCsArgs + { + AllowPreReleaseFlag = false, + Install = "", + ScriptName = null + }; + + var factory = new CommandFactory(CreateCompositionContainer()); + var result = factory.CreateCommand(args); + + result.ShouldImplement(); + } + + [Fact] + public void ShouldExecuteWhenScriptNameIsPassed() + { + var args = new ScriptCsArgs + { + AllowPreReleaseFlag = false, + Install = null, + ScriptName = "test.csx" + }; + + var factory = new CommandFactory(CreateCompositionContainer()); + var result = factory.CreateCommand(args); + + result.ShouldImplement(); + } + + [Fact] + public void ShouldExecuteWhenBothNameAndInstallArePassed() + { + var args = new ScriptCsArgs + { + AllowPreReleaseFlag = false, + Install = "", + ScriptName = "test.csx" + }; + + var factory = new CommandFactory(CreateCompositionContainer()); + var result = factory.CreateCommand(args); + + result.ShouldImplement(); + } + + [Fact] + public void ShouldReturnInvalidWhenNoNameOrInstallSet() + { + var args = new ScriptCsArgs + { + AllowPreReleaseFlag = false, + Install = null, + ScriptName = null + }; + + var factory = new CommandFactory(CreateCompositionContainer()); + var result = factory.CreateCommand(args); + + result.ShouldImplement(); + } + + + } + } +} diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index bb1d3b3a..ba843857 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -16,7 +16,10 @@ ..\..\packages\Should.1.1.12.0\lib\Should.dll + + + @@ -33,9 +36,18 @@ Properties\CommonVersionInfo.cs + + + {E590E710-E159-48E6-A3E6-1A83D3FE732C} + ScriptCs.Core + + + {E79EC231-E27D-4057-91C9-2D001A3A8C3B} + ScriptCs.Engine.Roslyn + {25080671-1a80-4041-b9c7-260578ff4849} ScriptCs From aef380c0454f066eded6f8994f840d7a5f1db581 Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 15 Mar 2013 22:37:09 -0400 Subject: [PATCH 0123/1224] added support for local nuget.config --- src/ScriptCs.Core/Constants.cs | 1 + .../NugetInstallationProvider.cs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Constants.cs b/src/ScriptCs.Core/Constants.cs index 8a78a48f..9b357007 100644 --- a/src/ScriptCs.Core/Constants.cs +++ b/src/ScriptCs.Core/Constants.cs @@ -3,6 +3,7 @@ namespace ScriptCs public static class Constants { public const string PackagesFile = "packages.config"; + public const string NugetFile = "nuget.config"; public const string PackagesFolder = "packages"; public const string DefaultRepositoryUrl = "https://nuget.org/api/v2/"; diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index f055cd5a..804276a5 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -8,11 +8,13 @@ namespace ScriptCs.Package.InstallationProvider { public class NugetInstallationProvider : IInstallationProvider { + private readonly IFileSystem _fileSystem; private readonly PackageManager _manager; private readonly IEnumerable _repositoryUrls; public NugetInstallationProvider(IFileSystem fileSystem) { + _fileSystem = fileSystem; var path = Path.Combine(fileSystem.CurrentDirectory, Constants.PackagesFolder); _repositoryUrls = GetRepositorySources(path); var remoteRepository = new AggregateRepository(PackageRepositoryFactory.Default, _repositoryUrls, true); @@ -22,7 +24,17 @@ public NugetInstallationProvider(IFileSystem fileSystem) public IEnumerable GetRepositorySources(string path) { var configFileSystem = new PhysicalFileSystem(path); - var settings = Settings.LoadDefaultSettings(configFileSystem); + + ISettings settings; + if (_fileSystem.FileExists(Path.Combine(_fileSystem.CurrentDirectory, Constants.NugetFile))) + { + settings = new Settings(configFileSystem, Constants.NugetFile); + } + else + { + settings = Settings.LoadDefaultSettings(configFileSystem); + } + if (settings == null) return new[] { Constants.DefaultRepositoryUrl }; var sourceProvider = new PackageSourceProvider(settings); From c015cd23afcdddcf6338030286ac6a60b7bf96dd Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 15 Mar 2013 22:49:30 -0400 Subject: [PATCH 0124/1224] committing missing tests --- test/ScriptCs.Tests/CommandFactoryTests.cs | 44 ++++------- test/ScriptCs.Tests/InstallCommandTests.cs | 73 +++++++++++++++++++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 6 ++ .../ScriptExecuteCommandTests.cs | 40 ++++++++++ 4 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 test/ScriptCs.Tests/InstallCommandTests.cs create mode 100644 test/ScriptCs.Tests/ScriptExecuteCommandTests.cs diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 27d67a5c..031dacfc 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -1,10 +1,6 @@ -using System.ComponentModel.Composition; -using System.ComponentModel.Composition.Hosting; -using System.ComponentModel.Composition.Registration; +using Moq; using ScriptCs.Command; -using ScriptCs.Engine.Roslyn; using ScriptCs.Package; -using ScriptCs.Package.InstallationProvider; using Should; using Xunit; @@ -14,26 +10,16 @@ public class CommandFactoryTests { public class CreateCommandMethod { - private static CompositionContainer CreateCompositionContainer() + private static ScriptServiceRoot CreateRoot() { - var conventions = new RegistrationBuilder(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForTypesDerivedFrom().Export(); - conventions.ForType().Export(); - conventions.ForType().Export(); - - var catalog = new AggregateCatalog(); - catalog.Catalogs.Add(new AssemblyCatalog(typeof(ScriptExecutor).Assembly, conventions)); - catalog.Catalogs.Add(new AssemblyCatalog(typeof(RoslynScriptEngine).Assembly, conventions)); - - var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection); - - return container; + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + + return root; } [Fact] @@ -46,7 +32,7 @@ public void ShouldInstallWhenInstallFlagIsOn() ScriptName = null }; - var factory = new CommandFactory(CreateCompositionContainer()); + var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args); result.ShouldImplement(); @@ -62,7 +48,7 @@ public void ShouldExecuteWhenScriptNameIsPassed() ScriptName = "test.csx" }; - var factory = new CommandFactory(CreateCompositionContainer()); + var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args); result.ShouldImplement(); @@ -78,7 +64,7 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() ScriptName = "test.csx" }; - var factory = new CommandFactory(CreateCompositionContainer()); + var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args); result.ShouldImplement(); @@ -94,13 +80,11 @@ public void ShouldReturnInvalidWhenNoNameOrInstallSet() ScriptName = null }; - var factory = new CommandFactory(CreateCompositionContainer()); + var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args); result.ShouldImplement(); } - - } } } diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs new file mode 100644 index 00000000..aa1c2f4c --- /dev/null +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Versioning; +using Moq; +using ScriptCs.Command; +using ScriptCs.Package; +using Xunit; + +namespace ScriptCs.Tests +{ + public class InstallCommandTests + { + public class ExecuteMethod + { + [Fact] + public void InstallCommandShouldInstallSinglePackageIfNamePassed() + { + var args = new ScriptCsArgs + { + AllowPreReleaseFlag = false, + Install = "mypackage", + ScriptName = null + }; + + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + packageInstaller.Verify(i => i.InstallPackages(It.Is>(x => x.Count() == 1 && x.First().PackageId == "mypackage"), It.IsAny(), It.IsAny>()), Times.Once()); + } + + [Fact] + public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() + { + var args = new ScriptCsArgs + { + AllowPreReleaseFlag = false, + Install = "", + ScriptName = null + }; + + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + + resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List + { + new PackageReference("a", new FrameworkName(".NETFramework,Version=v4.0"), new Version()), + new PackageReference("b", new FrameworkName(".NETFramework,Version=v4.0"), new Version()) + }); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + packageInstaller.Verify(i => i.InstallPackages(It.Is>(x => x.Count() == 2), It.IsAny(), It.IsAny>()), Times.Once()); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index ba843857..98bf82e1 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -37,9 +37,15 @@ Properties\CommonVersionInfo.cs + + + + {6049E205-8B5F-4080-B023-70600E51FD64} + ScriptCs.Contracts + {E590E710-E159-48E6-A3E6-1A83D3FE732C} ScriptCs.Core diff --git a/test/ScriptCs.Tests/ScriptExecuteCommandTests.cs b/test/ScriptCs.Tests/ScriptExecuteCommandTests.cs new file mode 100644 index 00000000..c12aaf07 --- /dev/null +++ b/test/ScriptCs.Tests/ScriptExecuteCommandTests.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using Moq; +using ScriptCs.Command; +using ScriptCs.Contracts; +using ScriptCs.Package; +using Xunit; + +namespace ScriptCs.Tests +{ + public class ScriptExecuteCommandTests + { + public class ExecuteMethod + { + [Fact] + public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() + { + var args = new ScriptCsArgs + { + AllowPreReleaseFlag = false, + Install = "", + ScriptName = "test.csx" + }; + + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny>(), It.IsAny>()), Times.Once()); + } + } + } +} \ No newline at end of file From 97facfb380e21892c0e119fd6dca1a8e0db0b4ba Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 14:34:35 -0400 Subject: [PATCH 0125/1224] Reset the CommonVersionInfo file content --- common/CommonVersionInfo.cs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index d2073f44..590a13eb 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,18 +1,9 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18010 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; using System.Reflection; -[assembly: System.Reflection.AssemblyVersionAttribute("0.3.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("0.3.0-alpha")] - -// Generated by the MSBuild WriteCodeFragment class on 3/15/2013 1:13:26 PM. +/** + * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the + * contents of 'build\ScriptCs.Version.props'. + **/ +[assembly: AssemblyVersion("0.0.0")] +[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file From dc8aee99296e264b3bebb1313545f87bb6b2cc3b Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 14:34:56 -0400 Subject: [PATCH 0126/1224] Use all lowercase characters for the chocolatey package ID --- src/ScriptCs/Properties/Scriptcs.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Properties/Scriptcs.nuspec b/src/ScriptCs/Properties/Scriptcs.nuspec index e2999295..d037f186 100644 --- a/src/ScriptCs/Properties/Scriptcs.nuspec +++ b/src/ScriptCs/Properties/Scriptcs.nuspec @@ -1,7 +1,7 @@  - ScriptCs + scriptcs 0.0.0 Glenn Block, Justin Rusbatch, Filip Wojcieszyn Glenn Block, Justin Rusbatch, Filip Wojcieszyn From 7ed728cb94d5cbe958e630f331734071a76e4f21 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 15:39:58 -0400 Subject: [PATCH 0127/1224] Rename Scriptcs.nuspec to scriptcs.nuspec --- src/ScriptCs/Properties/{Scriptcs.nuspec => scriptcs.nuspec} | 0 src/ScriptCs/ScriptCs.csproj | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/ScriptCs/Properties/{Scriptcs.nuspec => scriptcs.nuspec} (100%) diff --git a/src/ScriptCs/Properties/Scriptcs.nuspec b/src/ScriptCs/Properties/scriptcs.nuspec similarity index 100% rename from src/ScriptCs/Properties/Scriptcs.nuspec rename to src/ScriptCs/Properties/scriptcs.nuspec diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 9a2f8e4f..bd91f247 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -50,7 +50,7 @@ - + From 8020ae6a5bee8e9d0992cb8f6710f99c4a990d00 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 16:26:21 -0400 Subject: [PATCH 0128/1224] Paths should not be declared using static functions --- build/Build.proj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/Build.proj b/build/Build.proj index 6d856d14..94700155 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -8,11 +8,11 @@ Debug - $([System.IO.Path]::GetFullPath( '$(MSBuildThisFileDirectory)..\' )) - $([System.IO.Path]::Combine( $(Root), 'artifacts\' )) - $([System.IO.Path]::Combine( $(BaseArtifactsPath), $(Configuration) ))\ - $(ArtifactsPath.TrimEnd(new[] { '\' })) - $([System.IO.Path]::Combine( $(Root), '.nuget\nuget.exe' )) + $(MSBuildThisFileDirectory)..\ + $(Root)artifacts\ + $(BaseArtifactsPath)$(Configuration)\ + $(BaseArtifactsPath)$(Configuration) + $(Root).nuget\nuget.exe $([System.IO.Path]::Combine( $(Root), 'common\CommonVersionInfo.cs' )) From d1c66e5f0960f720138224a3bf53bcb97231ff1b Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 16:26:55 -0400 Subject: [PATCH 0129/1224] Create the artifacts directory after cleaning it --- build/Build.proj | 1 + 1 file changed, 1 insertion(+) diff --git a/build/Build.proj b/build/Build.proj index 94700155..b62ddcaa 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -34,6 +34,7 @@ + From 2464b38e3173042331ff13770475d65e53bb06c6 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 16:28:10 -0400 Subject: [PATCH 0130/1224] Change OutputPath back to the default location --- build/Build.proj | 2 +- build/ScriptCs.Common.props | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/build/Build.proj b/build/Build.proj index b62ddcaa..6f3c599b 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -45,7 +45,7 @@ - + diff --git a/build/ScriptCs.Common.props b/build/ScriptCs.Common.props index e54388b8..cbef322e 100644 --- a/build/ScriptCs.Common.props +++ b/build/ScriptCs.Common.props @@ -17,20 +17,13 @@ true prompt 4 - bin\$(Configuration)\ + bin\$(Configuration)\ true TRACE;$(DefineConstants) - - - - $([System.IO.Path]::Combine($(ArtifactsPath), 'bin\')) - - - false From 20e97641f5986771311f4ec7da42451ff96ecd28 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 17:32:02 -0400 Subject: [PATCH 0131/1224] Replace tabs with spaces in chocolateyinstall.ps1 --- src/ScriptCs/Properties/chocolateyinstall.ps1 | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ScriptCs/Properties/chocolateyinstall.ps1 b/src/ScriptCs/Properties/chocolateyinstall.ps1 index 923c480d..3bbc2b2e 100644 --- a/src/ScriptCs/Properties/chocolateyinstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyinstall.ps1 @@ -1,19 +1,19 @@ try { $tools = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" - $nugetExe = "$env:ChocolateyInstall\ChocolateyInstall\nuget" - $binPath="$env:appdata\scriptcs" + $nugetExe = "$env:ChocolateyInstall\ChocolateyInstall\nuget" + $binPath="$env:appdata\scriptcs" - if(!(Test-Path $binpath)){mkdir $binPath} - Copy-Item "$tools\scriptcs\*" $binPath -force - mkdir "$tools\nugets" - "nuget.core","Roslyn.Compilers.Common","Roslyn.Compilers.CSharp","PowerArgs" | - % {.$nugetexe install $_ -o "$tools\nugets"} - Get-childItem "$tools\nugets" -filter *.dll -recurse | % {Copy-Item $_.FullName $binPath } - New-Item "$tools\scriptcs\scriptcs.exe.ignore" -type file -force - Remove-Item $tools\..\lib -recurse -force - Install-ChocolateyPath $binPath - write-host "scriptcs.exe locted in $binpath is now in your path. " -foregroundcolor darkyellow - write-host "You may need to open a new console for the new path to take effect. Happy scripting!" -foregroundcolor darkyellow + if(!(Test-Path $binpath)){mkdir $binPath} + Copy-Item "$tools\scriptcs\*" $binPath -force + mkdir "$tools\nugets" + "nuget.core","Roslyn.Compilers.Common","Roslyn.Compilers.CSharp","PowerArgs" | + % {.$nugetexe install $_ -o "$tools\nugets"} + Get-childItem "$tools\nugets" -filter *.dll -recurse | % {Copy-Item $_.FullName $binPath } + New-Item "$tools\scriptcs\scriptcs.exe.ignore" -type file -force + Remove-Item $tools\..\lib -recurse -force + Install-ChocolateyPath $binPath + write-host "scriptcs.exe locted in $binpath is now in your path. " -foregroundcolor darkyellow + write-host "You may need to open a new console for the new path to take effect. Happy scripting!" -foregroundcolor darkyellow Write-ChocolateySuccess 'scriptcs' } catch { Write-ChocolateyFailure 'scriptcs' "$($_.Exception.Message)" From d8bb756c19d9a6d5d83be7d205b78c313feb08ca Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sat, 16 Mar 2013 18:32:26 -0300 Subject: [PATCH 0132/1224] # Configured log4net in console application and registered log in AutoFac --- src/ScriptCs/CompositionRoot.cs | 40 ++++++++++++++++++++++++++++-- src/ScriptCs/Program.cs | 13 ++++++---- src/ScriptCs/ScriptCs.csproj | 3 +++ src/ScriptCs/ScriptCsArgs.cs | 44 +++++++++++++++++++++++++++++++-- src/ScriptCs/packages.config | 1 + 5 files changed, 92 insertions(+), 9 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 9da6a0d9..9c05706c 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -5,21 +5,33 @@ using ScriptCs.Engine.Roslyn; using ScriptCs.Package; +using log4net; +using log4net.Appender; +using log4net.Core; +using log4net.Layout; +using log4net.Repository.Hierarchy; + namespace ScriptCs { public class CompositionRoot { private readonly bool _debug; + private readonly string _logLevel; private IContainer _container; - public CompositionRoot(bool debug) + public CompositionRoot(bool debug, string logLevel) { _debug = debug; + _logLevel = logLevel; } public void Initialize() { var builder = new ContainerBuilder(); + + var logger = CreateLogger(); + builder.RegisterInstance(logger); + var types = new[] { typeof (ScriptHostFactory), @@ -31,7 +43,7 @@ public void Initialize() }; builder.RegisterTypes(types).AsImplementedInterfaces(); - + if (_debug) { builder.RegisterType().As(); @@ -54,5 +66,29 @@ public ScriptServiceRoot GetServiceRoot() { return _container.Resolve(); } + + public ILog GetLogger() + { + return _container.Resolve(); + } + + private ILog CreateLogger() + { + const string Pattern = "%-5level Thread[%thread]: %message%newline"; + const string LoggerName = "scriptcs"; + var hierarchy = (Hierarchy)LogManager.GetRepository(); + var logger = LogManager.GetLogger(LoggerName); + var consoleAppender = new ConsoleAppender + { + Layout = new PatternLayout(Pattern), + Threshold = hierarchy.LevelMap[_logLevel] + }; + + hierarchy.Root.AddAppender(consoleAppender); + hierarchy.Root.Level = Level.All; + hierarchy.Configured = true; + + return logger; + } } } \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 831f1351..ee56fdd1 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,8 +1,7 @@ using System; using System.Linq; -using Autofac.Builder; + using PowerArgs; -using ScriptCs.Contracts; namespace ScriptCs { @@ -20,8 +19,12 @@ private static void Main(string[] args) var script = commandArgs.ScriptName; var debug = commandArgs.DebugFlag; - var compositionRoot = new CompositionRoot(debug); + var logLevel = commandArgs.LogLevel; + var compositionRoot = new CompositionRoot(debug, logLevel); compositionRoot.Initialize(); + var logger = compositionRoot.GetLogger(); + + logger.Debug("Creating ScriptServiceRoot"); var scriptServiceRoot = compositionRoot.GetServiceRoot(); try @@ -30,14 +33,14 @@ private static void Main(string[] args) var paths = scriptServiceRoot.PackageAssemblyResolver.GetAssemblyNames(workingDirectory).ToList(); foreach (var path in paths) { - Console.WriteLine("Found assembly reference: " + path); + logger.InfoFormat("Found assembly reference: {0}", path); } scriptServiceRoot.Executor.Execute(script, paths, scriptServiceRoot.ScriptPackResolver.GetPacks()); } catch (Exception ex) { - Console.WriteLine(ex.Message); + logger.Fatal(ex.Message); } } } diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 9a2f8e4f..99733b62 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -21,6 +21,9 @@ ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll + + ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + ..\..\packages\PowerArgs.1.2.0.1\lib\net40\PowerArgs.dll diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 910d12a1..e25478d2 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -1,9 +1,23 @@ -using PowerArgs; +using System; +using System.Linq; + +using PowerArgs; + +using log4net; namespace ScriptCs { + using System.Globalization; + + using log4net.Core; + public class ScriptCsArgs { + private const string ValidLogLevels = + "off, debug, emergency, fatal, alert, critical, severe, error, warn, notice, info, debug, fine, trace, verbose"; + + private string _logLevel; + [ArgDescription("Script file name")] [ArgPosition(0)] public string ScriptName { get; set; } @@ -12,9 +26,35 @@ public class ScriptCsArgs [ArgShortcut("debug")] public bool DebugFlag { get; set; } + [ArgDescription("Flag which defines the log level used. Possible values:" + ValidLogLevels)] + [ArgShortcut("log")] + [DefaultValue("off")] + public string LogLevel + { + get + { + return _logLevel; + } + set + { + _logLevel = value.ToUpper(CultureInfo.CurrentUICulture); + } + } + public bool IsValid() { - return !string.IsNullOrWhiteSpace(ScriptName); + return !(this.IsLogLevelValid() && string.IsNullOrWhiteSpace(ScriptName)); + } + + private bool IsLogLevelValid() + { + var repository = LogManager.GetRepository(); + var levelMap = repository.LevelMap; + return levelMap + .AllLevels + .Cast() + .Any(level => + level.Name.Equals(LogLevel, StringComparison.CurrentCulture)); } } } \ No newline at end of file diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index a22262dc..467279a8 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file From 8cf875c00a6693fa433c3a11e2498aa8d22a1bd2 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sat, 16 Mar 2013 19:04:49 -0300 Subject: [PATCH 0133/1224] # Initial debugging messages for FilePreProcessor.cs, RoslynScriptDebuggerEngine.cs and RoslynScriptEngine.cs --- src/ScriptCs.Core/FilePreProcessor.cs | 26 +++++++++---------- src/ScriptCs.Core/ScriptCs.Core.csproj | 3 +++ src/ScriptCs.Core/packages.config | 1 + .../RoslynScriptDebuggerEngine.cs | 12 ++++++--- .../RoslynScriptEngine.cs | 21 ++++++++++++--- .../ScriptCs.Engine.Roslyn.csproj | 3 +++ src/ScriptCs.Engine.Roslyn/packages.config | 1 + src/ScriptCs/CompositionRoot.cs | 1 - src/ScriptCs/Program.cs | 1 - src/ScriptCs/ScriptCsArgs.cs | 4 +-- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 26 ++++++++++++------- .../ScriptCs.Core.Tests.csproj | 3 +++ test/ScriptCs.Core.Tests/packages.config | 1 + .../RoslynScriptDebuggerEngine.cs | 10 ++++--- .../RoslynScriptEngineTests.cs | 10 +++---- .../ScriptCs.Engine.Roslyn.Tests.csproj | 3 +++ .../packages.config | 1 + test/ScriptCs.Tests/ScriptCs.Tests.csproj | 4 +++ test/ScriptCs.Tests/packages.config | 1 + 19 files changed, 88 insertions(+), 44 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 7bb62b1c..38102e45 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -3,34 +3,43 @@ namespace ScriptCs { + using log4net; + public class FilePreProcessor : IFilePreProcessor { private const string LoadString = "#load "; private const string UsingString = "using "; private const string RString = "#r "; + private readonly ILog _logger; + protected readonly IFileSystem _fileSystem; - public FilePreProcessor(IFileSystem fileSystem) + public FilePreProcessor(IFileSystem fileSystem, ILog logger) { _fileSystem = fileSystem; + _logger = logger; } public string ProcessFile(string path) { + _logger.InfoFormat("{0} - Reading lines", path); var entryFile = _fileSystem.ReadFileLines(path); var usings = new List(); var rs = new List(); var loads = new List(); + _logger.InfoFormat("{0} - Parsing ", path); var parsed = ParseFile(path, entryFile, ref usings, ref rs, ref loads); + _logger.InfoFormat("{0} - Generating references (#r)", path); var result = GenerateRs(rs); if (!string.IsNullOrWhiteSpace(result)) { result += _fileSystem.NewLine; } + _logger.InfoFormat("{0} - Generating using statements", path); result += GenerateUsings(usings); if (!string.IsNullOrWhiteSpace(result)) { @@ -63,7 +72,8 @@ private string ParseFile(string path, IEnumerable file, ref List // +1 because we are in a zero indexed list, but line numbers are 1 indexed // we need to keep the original position of the actual line if (firstBody != -1) - { + { + _logger.InfoFormat("Added #line statement for file {0} at line {1}", path, firstBody); fileList.Insert(firstBody, string.Format(@"#line {0} ""{1}""", firstBody + 1, path)); } @@ -97,6 +107,7 @@ private string ParseFile(string path, IEnumerable file, ref List if (filecontent != null) { loads.Add(line); + _logger.InfoFormat("Parsing file {0}", path); var parsed = ParseFile(filepath, filecontent, ref usings, ref rs, ref loads); fileList[i] =/* string.Format("//{0}{1}", filepath, _fileSystem.NewLine) + */parsed; } @@ -131,16 +142,5 @@ private static bool IsLoadLine(string line) { return line.TrimStart(' ').StartsWith(LoadString); } - - private enum ParsingStatus - { - ForbidReferences, - - ForbidLoads, - - ForbidUsings, - - NoRestrictions - } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 502908e9..05c4a082 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -18,6 +18,9 @@ ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll + + ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 2c44436d..cd130584 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index 83b75df1..a5e93f35 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Reflection; +using log4net; using Roslyn.Scripting; using ScriptCs.Exceptions; @@ -11,14 +12,17 @@ public class RoslynScriptDebuggerEngine : RoslynScriptEngine { private const string CompiledScriptClass = "Submission#0"; private const string CompiledScriptMethod = ""; + private readonly ILog _logger; - public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory) - : base(scriptHostFactory) + public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory, ILog logger) + : base(scriptHostFactory, logger) { + this._logger = logger; } protected override void Execute(string code, Session session) { + _logger.Info("Compiling submission"); var submission = session.CompileSubmission(code); var exeBytes = new byte[0]; var pdbBytes = new byte[0]; @@ -32,13 +36,14 @@ protected override void Execute(string code, Session session) if (result.Success) { + _logger.Info("Compilation was successful."); exeBytes = exeStream.ToArray(); pdbBytes = pdbStream.ToArray(); } else { var errors = String.Join(Environment.NewLine, result.Diagnostics.Select(x => x.ToString())); - Console.WriteLine(errors); + _logger.ErrorFormat("Error occurred when compiling: {0})", errors); } } @@ -54,6 +59,7 @@ protected override void Execute(string code, Session session) } catch (Exception e) { + _logger.Error("An error occurred when executing the scripts."); var message = string.Format( "Exception Message: {0} {1}Stack Trace:{2}", diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index f95d7b4a..ff413e24 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -5,16 +5,20 @@ namespace ScriptCs.Engine.Roslyn { + using log4net; + public class RoslynScriptEngine : IScriptEngine { private readonly ScriptEngine _scriptEngine; private readonly IScriptHostFactory _scriptHostFactory; + private readonly ILog _logger; - public RoslynScriptEngine(IScriptHostFactory scriptHostFactory) + public RoslynScriptEngine(IScriptHostFactory scriptHostFactory, ILog logger) { _scriptEngine = new ScriptEngine(); _scriptHostFactory = scriptHostFactory; + _logger = logger; } public string BaseDirectory @@ -25,17 +29,28 @@ public string BaseDirectory public void Execute(string code, IEnumerable references, ScriptPackSession scriptPackSession) { + _logger.Info("Retrieving script packs contexts"); var contexts = scriptPackSession.ScriptPacks.Select(x => x.GetContext()); + + _logger.Info("Creating script host"); var host = _scriptHostFactory.CreateScriptHost(contexts); + _logger.Info("Creating session"); var session = _scriptEngine.CreateSession(host); foreach (var reference in references.Union(scriptPackSession.References).Distinct()) + { + _logger.InfoFormat("Adding reference to {0}", reference); session.AddReference(reference); - + } + foreach (var @namespace in scriptPackSession.Namespaces.Distinct()) - session.ImportNamespace(@namespace); + { + _logger.InfoFormat("Importing namespace {0}", @namespace); + session.ImportNamespace(@namespace); + } + _logger.Info("Executing code"); Execute(code, session); } diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 38a08ea6..74a70d5f 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -9,6 +9,9 @@ ..\..\ + + ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll diff --git a/src/ScriptCs.Engine.Roslyn/packages.config b/src/ScriptCs.Engine.Roslyn/packages.config index 203aca0a..bf177711 100644 --- a/src/ScriptCs.Engine.Roslyn/packages.config +++ b/src/ScriptCs.Engine.Roslyn/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 9c05706c..c1032135 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -4,7 +4,6 @@ using Autofac.Integration.Mef; using ScriptCs.Engine.Roslyn; using ScriptCs.Package; - using log4net; using log4net.Appender; using log4net.Core; diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index ee56fdd1..8e24a8f0 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,6 +1,5 @@ using System; using System.Linq; - using PowerArgs; namespace ScriptCs diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index e25478d2..7ce1d744 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -1,9 +1,7 @@ using System; using System.Linq; - -using PowerArgs; - using log4net; +using PowerArgs; namespace ScriptCs { diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index 02327750..74f52e3e 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -7,6 +7,8 @@ namespace ScriptCs.Tests { + using log4net; + public class FileProcessorTests { public class ProcessFileMethod @@ -52,6 +54,8 @@ public class ProcessFileMethod private readonly Mock _fileSystem; + private readonly Mock _logger; + public ProcessFileMethod() { _fileSystem = new Mock(); @@ -64,12 +68,14 @@ public ProcessFileMethod() .Returns(_file3.ToArray()); _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) .Returns(_file4.ToArray()); + + _logger = new Mock(); } [Fact] public void MultipleUsingStatementsShouldProduceDistinctOutput() { - var processor = new FilePreProcessor(_fileSystem.Object); + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var output = processor.ProcessFile("\\script1.csx"); var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); @@ -81,7 +87,7 @@ public void MultipleUsingStatementsShouldProduceDistinctOutput() [Fact] public void UsingStateMentsShoulAllBeAtTheTop() { - var processor = new FilePreProcessor(_fileSystem.Object); + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var output = processor.ProcessFile("\\script1.csx"); var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); @@ -94,7 +100,7 @@ public void UsingStateMentsShoulAllBeAtTheTop() [Fact] public void ShouldNotLoadInlineLoads() { - var processor = new FilePreProcessor(_fileSystem.Object); + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); processor.ProcessFile("\\script1.csx"); _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); @@ -120,7 +126,7 @@ public void ShouldNotLoadSameFileTwice() fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) .Returns(_file4.ToArray()); - var processor = new FilePreProcessor(_fileSystem.Object); + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); processor.ProcessFile("\\script1.csx"); _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); @@ -142,7 +148,7 @@ public void LoadBeforeUsingShouldBeAllowed() _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); - var processor = new FilePreProcessor(_fileSystem.Object); + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var output = processor.ProcessFile("\\file.csx"); var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); @@ -164,7 +170,7 @@ public void ShouldNotBeAllowedToLoadAfterUsing() }; _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); - var processor = new FilePreProcessor(_fileSystem.Object); + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var output = processor.ProcessFile("\\file.csx"); var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); @@ -191,7 +197,7 @@ public void UsingInCodeDoesNotCountAsUsingImport() }; _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); - var processor = new FilePreProcessor(_fileSystem.Object); + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var output = processor.ProcessFile("\\file.csx"); var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); @@ -218,7 +224,7 @@ public void ShouldHaveReferencesOnTop() fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))).Returns(file1.ToArray()); fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))).Returns(_file2.ToArray()); - var processor = new FilePreProcessor(fs.Object); + var processor = new FilePreProcessor(fs.Object, _logger.Object); var output = processor.ProcessFile("\\script1.csx"); var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None).ToList(); @@ -252,7 +258,7 @@ public void ShouldHaveReferencesFromAllFiles() _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\scriptX.csx"))) .Returns(file2.ToArray()); - var processor = new FilePreProcessor(_fileSystem.Object); + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var output = processor.ProcessFile("\\script1.csx"); var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); @@ -314,7 +320,7 @@ public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() .Returns(f5.ToArray()); _fileSystem.Setup(fs => fs.IsPathRooted(It.IsAny())).Returns(true); - var preProcessor = new FilePreProcessor(_fileSystem.Object); + var preProcessor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var file = preProcessor.ProcessFile(@"C:\f1.csx"); diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 2f142f9b..b3b72297 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -9,6 +9,9 @@ ..\..\ + + ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll diff --git a/test/ScriptCs.Core.Tests/packages.config b/test/ScriptCs.Core.Tests/packages.config index 32559f4f..42f2ff5a 100644 --- a/test/ScriptCs.Core.Tests/packages.config +++ b/test/ScriptCs.Core.Tests/packages.config @@ -1,5 +1,6 @@  + diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs index e418cf92..21ae82e8 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs @@ -1,15 +1,15 @@ using System; using System.Linq; +using log4net; using Moq; using ScriptCs.Contracts; using ScriptCs.Engine.Roslyn; +using ScriptCs.Exceptions; using Should; using Xunit; namespace ScriptCs.Tests { - using ScriptCs.Exceptions; - public class RoslynScriptDebuggerEngineTests { private static RoslynScriptDebuggerEngine CreateScriptEngine( @@ -17,7 +17,9 @@ private static RoslynScriptDebuggerEngine CreateScriptEngine( { scriptHostFactory = scriptHostFactory ?? new Mock(); - return new RoslynScriptDebuggerEngine(scriptHostFactory.Object); + var logger = new Mock(); + + return new RoslynScriptDebuggerEngine(scriptHostFactory.Object, logger.Object); } public class TheExecuteMethod @@ -43,4 +45,4 @@ public void ShouldThrowExceptionThrownByScriptWhenErrorOccurs() } } } -} +} \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 49bc5827..47b67a89 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -1,24 +1,22 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Moq; using ScriptCs.Contracts; using ScriptCs.Engine.Roslyn; -using Should; using Xunit; +using log4net; namespace ScriptCs.Tests { - using Roslyn.Scripting.CSharp; - public class RoslynScriptEngineTests { private static RoslynScriptEngine CreateScriptEngine( Mock scriptHostFactory = null) { scriptHostFactory = scriptHostFactory ?? new Mock(); + var logger = new Mock(); - return new RoslynScriptEngine(scriptHostFactory.Object); + return new RoslynScriptEngine(scriptHostFactory.Object, logger.Object); } public class TheExecuteMethod diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj index 4f9bc964..f98204b8 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj @@ -9,6 +9,9 @@ ..\..\ + + ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll diff --git a/test/ScriptCs.Engine.Roslyn.Tests/packages.config b/test/ScriptCs.Engine.Roslyn.Tests/packages.config index 5a4e8724..50922081 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/packages.config +++ b/test/ScriptCs.Engine.Roslyn.Tests/packages.config @@ -1,5 +1,6 @@  + diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index bb1d3b3a..6503c862 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -9,6 +9,10 @@ ..\..\ + + False + ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll diff --git a/test/ScriptCs.Tests/packages.config b/test/ScriptCs.Tests/packages.config index 08b40aa8..eb044e0d 100644 --- a/test/ScriptCs.Tests/packages.config +++ b/test/ScriptCs.Tests/packages.config @@ -1,5 +1,6 @@  + From 5fdd53efbbdd3aa9ee902b00029cb3a86ed22138 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 18:23:06 -0400 Subject: [PATCH 0134/1224] Create chocolateyUninstall.ps1 --- src/ScriptCs/Properties/chocolateyUninstall.ps1 | 15 +++++++++++++++ src/ScriptCs/ScriptCs.csproj | 1 + 2 files changed, 16 insertions(+) create mode 100644 src/ScriptCs/Properties/chocolateyUninstall.ps1 diff --git a/src/ScriptCs/Properties/chocolateyUninstall.ps1 b/src/ScriptCs/Properties/chocolateyUninstall.ps1 new file mode 100644 index 00000000..037023e2 --- /dev/null +++ b/src/ScriptCs/Properties/chocolateyUninstall.ps1 @@ -0,0 +1,15 @@ +try { + $binPath = "$env:APPDATA\scriptcs" + + Write-Host "Removing '$binPath'..." -ForegroundColor DarkYellow + + if (Test-Path $binPath) { + Remove-Item $binPath -Recurse -Force + } + + Write-Host "'$binPath' has been removed." -ForegroundColor DarkYellow + Write-ChocolateySuccess 'scriptcs' +} catch { + Write-ChocolateyFailure 'scriptcs' "$($_.Exception.Message)" + throw +} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index bd91f247..64afafbb 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -50,6 +50,7 @@ + From 2adc0a97527e741fcf2095a6829d477b4ac9c324 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 18:24:28 -0400 Subject: [PATCH 0135/1224] scriptcs.nuspec should assume the working directory is the project directory --- src/ScriptCs/Properties/scriptcs.nuspec | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ScriptCs/Properties/scriptcs.nuspec b/src/ScriptCs/Properties/scriptcs.nuspec index d037f186..1adaf7ce 100644 --- a/src/ScriptCs/Properties/scriptcs.nuspec +++ b/src/ScriptCs/Properties/scriptcs.nuspec @@ -15,11 +15,10 @@ - - - - - - + + + + + \ No newline at end of file From b7ef531ff7430082b7e906d3caa4ed2ce46b094e Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 18:25:43 -0400 Subject: [PATCH 0136/1224] chocolateyinstall.ps1 to make it less verbose --- src/ScriptCs/Properties/chocolateyinstall.ps1 | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/ScriptCs/Properties/chocolateyinstall.ps1 b/src/ScriptCs/Properties/chocolateyinstall.ps1 index 3bbc2b2e..5ab98ff0 100644 --- a/src/ScriptCs/Properties/chocolateyinstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyinstall.ps1 @@ -1,19 +1,28 @@ try { $tools = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" - $nugetExe = "$env:ChocolateyInstall\ChocolateyInstall\nuget" - $binPath="$env:appdata\scriptcs" + $nuget = "$env:ChocolateyInstall\ChocolateyInstall\nuget" + $binPath = "$env:APPDATA\scriptcs" + $nugetPath = "$tools\nugets" + + New-Item $binPath -ItemType Directory -Force | Out-Null + + Copy-Item "$tools\scriptcs\*" $binPath -Force + + Write-Host "Retrieving NuGet dependencies..." -ForegroundColor DarkYellow + + "NuGet.Core","Autofac.Mef","Roslyn.Compilers.CSharp","PowerArgs" | %{ .$nuget install $_ -o $nugetPath -nocache } | Out-Null + + Get-ChildItem $nugetPath -Filter "*.dll" -Recurse | %{ Copy-Item $_.FullName $binPath -Force } + Remove-Item $nugetPath -Recurse -Force + New-Item "$tools\scriptcs\scriptcs.exe.ignore" -ItemType File -Force | Out-Null + + if (Test-Path "$tools\..\lib") { + Remove-Item "$tools\..\lib" -Recurse -Force + } - if(!(Test-Path $binpath)){mkdir $binPath} - Copy-Item "$tools\scriptcs\*" $binPath -force - mkdir "$tools\nugets" - "nuget.core","Roslyn.Compilers.Common","Roslyn.Compilers.CSharp","PowerArgs" | - % {.$nugetexe install $_ -o "$tools\nugets"} - Get-childItem "$tools\nugets" -filter *.dll -recurse | % {Copy-Item $_.FullName $binPath } - New-Item "$tools\scriptcs\scriptcs.exe.ignore" -type file -force - Remove-Item $tools\..\lib -recurse -force Install-ChocolateyPath $binPath - write-host "scriptcs.exe locted in $binpath is now in your path. " -foregroundcolor darkyellow - write-host "You may need to open a new console for the new path to take effect. Happy scripting!" -foregroundcolor darkyellow + Write-Host "scriptcs.exe has been installed to $binpath and has been added to your path." -ForegroundColor DarkYellow + Write-Host "You may need to open a new console for the new path to take effect. Happy scripting!" -ForegroundColor DarkYellow Write-ChocolateySuccess 'scriptcs' } catch { Write-ChocolateyFailure 'scriptcs' "$($_.Exception.Message)" From b35ebcbed5153c5bd80c9d31c6572cc06ad5a185 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 18:26:45 -0400 Subject: [PATCH 0137/1224] Split the Package target into two separate targets for NuGet and Chocolatey packages --- build/Build.proj | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/build/Build.proj b/build/Build.proj index 6f3c599b..1c340e06 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -48,16 +48,10 @@ - + - - - - - - - + @@ -71,4 +65,22 @@ + + + -Version $(PackageVersion) -Symbols -NoPackageAnalysis -OutputDirectory "$(PackageOutputPath)" -p Configuration=$(Configuration) + + + + + + + + + + + + + + + \ No newline at end of file From 40787c81e1ed961c638bf18db5811fc4e545af80 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 16 Mar 2013 18:27:25 -0400 Subject: [PATCH 0138/1224] Rename chocolateyinstall.ps1 to chocolateyInstall.ps1 --- .../Properties/{chocolateyinstall.ps1 => chocolateyInstall.ps1} | 0 src/ScriptCs/ScriptCs.csproj | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/ScriptCs/Properties/{chocolateyinstall.ps1 => chocolateyInstall.ps1} (100%) diff --git a/src/ScriptCs/Properties/chocolateyinstall.ps1 b/src/ScriptCs/Properties/chocolateyInstall.ps1 similarity index 100% rename from src/ScriptCs/Properties/chocolateyinstall.ps1 rename to src/ScriptCs/Properties/chocolateyInstall.ps1 diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 64afafbb..eba94f68 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -49,8 +49,8 @@ - + From c8c17c163f916eca586c19694499fd589c2fbb08 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sat, 16 Mar 2013 19:30:54 -0300 Subject: [PATCH 0139/1224] # Modified level for some messages, added LoggerConfigurator.cs --- src/ScriptCs.Core/DebugScriptExecutor.cs | 6 ++- src/ScriptCs.Core/FilePreProcessor.cs | 14 +++--- src/ScriptCs.Core/ScriptExecutor.cs | 19 +++++++- .../RoslynScriptDebuggerEngine.cs | 4 +- .../RoslynScriptEngine.cs | 11 +++-- src/ScriptCs/CompositionRoot.cs | 24 ++--------- src/ScriptCs/LoggerConfigurator.cs | 43 +++++++++++++++++++ src/ScriptCs/ScriptCs.csproj | 1 + .../ScriptCs.Core.Tests/FileProcessorTests.cs | 3 +- .../ScriptExecutorTests.cs | 6 ++- 10 files changed, 88 insertions(+), 43 deletions(-) create mode 100644 src/ScriptCs/LoggerConfigurator.cs diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index 17d1b330..6dd04327 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -1,9 +1,11 @@ namespace ScriptCs { + using log4net; + public class DebugScriptExecutor : ScriptExecutor { - public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) - : base(fileSystem, filePreProcessor, scriptEngine) + public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) + : base(fileSystem, filePreProcessor, scriptEngine, logger) { } } diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 38102e45..e28eda9d 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -23,23 +23,23 @@ public FilePreProcessor(IFileSystem fileSystem, ILog logger) public string ProcessFile(string path) { - _logger.InfoFormat("{0} - Reading lines", path); + _logger.DebugFormat("{0} - Reading lines", path); var entryFile = _fileSystem.ReadFileLines(path); var usings = new List(); var rs = new List(); var loads = new List(); - _logger.InfoFormat("{0} - Parsing ", path); + _logger.DebugFormat("{0} - Parsing ", path); var parsed = ParseFile(path, entryFile, ref usings, ref rs, ref loads); - _logger.InfoFormat("{0} - Generating references (#r)", path); + _logger.DebugFormat("{0} - Generating references (#r)", path); var result = GenerateRs(rs); if (!string.IsNullOrWhiteSpace(result)) { result += _fileSystem.NewLine; } - _logger.InfoFormat("{0} - Generating using statements", path); + _logger.DebugFormat("{0} - Generating using statements", path); result += GenerateUsings(usings); if (!string.IsNullOrWhiteSpace(result)) { @@ -73,7 +73,7 @@ private string ParseFile(string path, IEnumerable file, ref List // we need to keep the original position of the actual line if (firstBody != -1) { - _logger.InfoFormat("Added #line statement for file {0} at line {1}", path, firstBody); + _logger.DebugFormat("Added #line statement for file {0} at line {1}", path, firstBody); fileList.Insert(firstBody, string.Format(@"#line {0} ""{1}""", firstBody + 1, path)); } @@ -107,9 +107,9 @@ private string ParseFile(string path, IEnumerable file, ref List if (filecontent != null) { loads.Add(line); - _logger.InfoFormat("Parsing file {0}", path); + _logger.DebugFormat("Parsing file {0}", path); var parsed = ParseFile(filepath, filecontent, ref usings, ref rs, ref loads); - fileList[i] =/* string.Format("//{0}{1}", filepath, _fileSystem.NewLine) + */parsed; + fileList[i] = parsed; } } else diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 1ccc1d26..c1b61156 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,21 +1,25 @@ using System.Collections.Generic; using System.IO; - +using log4net; using ScriptCs.Contracts; namespace ScriptCs { + using System; + public class ScriptExecutor : IScriptExecutor { private readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; private readonly IScriptEngine _scriptEngine; + private readonly ILog _logger; - public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) + public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) { _fileSystem = fileSystem; _filePreProcessor = filePreProcessor; _scriptEngine = scriptEngine; + _logger = logger; } public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) @@ -24,12 +28,16 @@ public void Execute(string script, IEnumerable paths, IEnumerable(); + _logger.Debug("Adding System reference"); references.Add("System"); + _logger.Debug("Adding System.Core"); references.Add("System.Core"); + _logger.DebugFormat("Adding references to files {0}", string.Join(Environment.NewLine, files)); references.AddRange(files); _scriptEngine.BaseDirectory = bin; + _logger.Debug("Initializing script packs"); var scriptPackSession = new ScriptPackSession(scriptPacks); scriptPackSession.InitializePacks(); @@ -49,7 +57,10 @@ private IEnumerable PrepareBinFolder(IEnumerable paths, string b var files = new List(); if (!_fileSystem.DirectoryExists(bin)) + { + _logger.DebugFormat("Creating directory {0}", bin); _fileSystem.CreateDirectory(bin); + } foreach (var file in paths) { @@ -57,7 +68,11 @@ private IEnumerable PrepareBinFolder(IEnumerable paths, string b var sourceFileLastWriteTime = _fileSystem.GetLastWriteTime(file); var destFileLastWriteTime = _fileSystem.GetLastWriteTime(destFile); if (sourceFileLastWriteTime != destFileLastWriteTime) + { + _logger.DebugFormat("Copying file {0} to bin folder {1}", file, destFile); _fileSystem.Copy(file, destFile, true); + } + files.Add(destFile); } diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index a5e93f35..a8cf37b9 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -22,7 +22,7 @@ public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory, ILog log protected override void Execute(string code, Session session) { - _logger.Info("Compiling submission"); + _logger.Debug("Compiling submission"); var submission = session.CompileSubmission(code); var exeBytes = new byte[0]; var pdbBytes = new byte[0]; @@ -36,7 +36,7 @@ protected override void Execute(string code, Session session) if (result.Success) { - _logger.Info("Compilation was successful."); + _logger.Debug("Compilation was successful."); exeBytes = exeStream.ToArray(); pdbBytes = pdbStream.ToArray(); } diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ff413e24..2c7155d4 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -1,12 +1,11 @@ using System.Collections.Generic; using System.Linq; +using log4net; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; namespace ScriptCs.Engine.Roslyn { - using log4net; - public class RoslynScriptEngine : IScriptEngine { private readonly ScriptEngine _scriptEngine; @@ -29,13 +28,13 @@ public string BaseDirectory public void Execute(string code, IEnumerable references, ScriptPackSession scriptPackSession) { - _logger.Info("Retrieving script packs contexts"); + _logger.Debug("Retrieving script packs contexts"); var contexts = scriptPackSession.ScriptPacks.Select(x => x.GetContext()); - _logger.Info("Creating script host"); + _logger.Debug("Creating script host"); var host = _scriptHostFactory.CreateScriptHost(contexts); - _logger.Info("Creating session"); + _logger.Debug("Creating session"); var session = _scriptEngine.CreateSession(host); foreach (var reference in references.Union(scriptPackSession.References).Distinct()) @@ -50,7 +49,7 @@ public void Execute(string code, IEnumerable references, ScriptPackSessi session.ImportNamespace(@namespace); } - _logger.Info("Executing code"); + _logger.Debug("Executing code"); Execute(code, session); } diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index c1032135..c93b6f24 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -28,7 +28,10 @@ public void Initialize() { var builder = new ContainerBuilder(); - var logger = CreateLogger(); + var loggerConfigurator = new LoggerConfigurator(_logLevel); + loggerConfigurator.Configure(); + var logger = loggerConfigurator.GetLogger(); + builder.RegisterInstance(logger); var types = new[] @@ -70,24 +73,5 @@ public ILog GetLogger() { return _container.Resolve(); } - - private ILog CreateLogger() - { - const string Pattern = "%-5level Thread[%thread]: %message%newline"; - const string LoggerName = "scriptcs"; - var hierarchy = (Hierarchy)LogManager.GetRepository(); - var logger = LogManager.GetLogger(LoggerName); - var consoleAppender = new ConsoleAppender - { - Layout = new PatternLayout(Pattern), - Threshold = hierarchy.LevelMap[_logLevel] - }; - - hierarchy.Root.AddAppender(consoleAppender); - hierarchy.Root.Level = Level.All; - hierarchy.Configured = true; - - return logger; - } } } \ No newline at end of file diff --git a/src/ScriptCs/LoggerConfigurator.cs b/src/ScriptCs/LoggerConfigurator.cs new file mode 100644 index 00000000..547f3a0a --- /dev/null +++ b/src/ScriptCs/LoggerConfigurator.cs @@ -0,0 +1,43 @@ +using log4net; +using log4net.Appender; +using log4net.Core; +using log4net.Layout; +using log4net.Repository.Hierarchy; + +namespace ScriptCs +{ + public class LoggerConfigurator + { + private const string Pattern = "%-5level Thread[%thread]: %message%newline"; + private const string LoggerName = "scriptcs"; + + private readonly string _logLevel; + + private ILog _logger; + + public LoggerConfigurator(string logLevel) + { + _logLevel = logLevel; + } + + public void Configure() + { + var hierarchy = (Hierarchy)LogManager.GetRepository(); + _logger = LogManager.GetLogger(LoggerName); + var consoleAppender = new ConsoleAppender + { + Layout = new PatternLayout(Pattern), + Threshold = hierarchy.LevelMap[_logLevel] + }; + + hierarchy.Root.AddAppender(consoleAppender); + hierarchy.Root.Level = Level.All; + hierarchy.Configured = true; + } + + public ILog GetLogger() + { + return _logger; + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 99733b62..aee457f3 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -45,6 +45,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index 74f52e3e..d2914dfc 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; +using log4net; using Moq; using Should; using Xunit; namespace ScriptCs.Tests { - using log4net; - public class FileProcessorTests { public class ProcessFileMethod diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index b05ffdcf..58957537 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading.Tasks; +using log4net; using Moq; using ScriptCs.Contracts; using Should; @@ -31,7 +31,9 @@ public static ScriptExecutor CreateScriptExecutor( scriptEngine.SetupProperty(e => e.BaseDirectory); } - return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object); + var logger = new Mock(); + + return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, logger.Object); } public class TheExecuteMethod From 827d47055831be9e3a0a74fc6140fc0304163976 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 16 Mar 2013 21:57:14 -0300 Subject: [PATCH 0140/1224] added contributors link --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 13047d96..9f0787a3 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ scriptcs relies on Rosyln for loading loose C# script files. It will automatical * Adding support for pluggable recipe "packs" for different frameworks. ## Contributing -Read our [Contribution Guidelines](https://github.com/scriptcs/scriptcs/blob/master/CONTRIBUTING.md). +* Read our [Contribution Guidelines](https://github.com/scriptcs/scriptcs/blob/master/CONTRIBUTING.md). +* List of all [contributors to date](https://github.com/scriptcs/scriptcs/wiki/Contributors). Thanks! ## Credits * Special thanks to [@filip_woj](http://twitter.com/filip_woj) for being the inspiration behind this with his Roslyn Web API posts. From 366554a25abecebc36e52ff045212d323f2ea63c Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 16 Mar 2013 22:49:22 -0300 Subject: [PATCH 0141/1224] added script referencing --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9f0787a3..58291a9a 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ This will launch a web api host. scriptcs relies on Rosyln for loading loose C# script files. It will automatically discover nuget packages local to the app and load the binaries. ## Docs +* [Referencing other scripts from your script](https://github.com/scriptcs/scriptcs/wiki/Referencing-scripts) * [Debugging overview & How To](https://github.com/scriptcs/scriptcs/blob/dev/docs/DEBUGGING.md) ## What's next From 94da15dff2a63b117bec9107530b29f65122cd38 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 17 Mar 2013 21:01:41 +0100 Subject: [PATCH 0142/1224] Removed packages.config from project --- src/ScriptCs.Contracts/ScriptCs.Contracts.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 40d0d704..94e645aa 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -31,7 +31,6 @@ - From b1977fa85c079d5960acc8731c285c04686761d7 Mon Sep 17 00:00:00 2001 From: Paul Stovell Date: Mon, 18 Mar 2013 19:20:01 +1000 Subject: [PATCH 0143/1224] Support for ScriptCS files that only contain a #load. If a file only contains #load lines, the firstCode variable will be -1, so the file was never loaded. Now this scenario will be supported. --- src/ScriptCs.Core/FilePreProcessor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 7bb62b1c..72e18f0b 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace ScriptCs @@ -87,7 +88,7 @@ private string ParseFile(string path, IEnumerable file, ref List } else if (IsLoadLine(line)) { - if (i < firstCode && !loads.Contains(line)) + if ((i < firstCode || firstCode < 0) && !loads.Contains(line)) { var filepath = line.Trim(' ').Replace(LoadString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); var filecontent = _fileSystem.IsPathRooted(filepath) From 458dcfc5aefb843eb03485ec30224147c82d6887 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 22 Mar 2013 17:13:06 +0100 Subject: [PATCH 0144/1224] Initial commit for -restore and -install revamp --- src/ScriptCs.Core/Package/PackageInstaller.cs | 11 ++-- src/ScriptCs.Core/PackageAssemblyResolver.cs | 51 +++++++------- src/ScriptCs.Core/ScriptExecutor.cs | 46 +++---------- src/ScriptCs.Core/ScriptPackSession.cs | 46 ++++++++----- src/ScriptCs/Command/CommandFactory.cs | 20 ++++-- src/ScriptCs/Command/ICommand.cs | 14 ++-- src/ScriptCs/Command/InstallCommand.cs | 54 ++++++++++----- src/ScriptCs/Command/RestoreCommand.cs | 66 +++++++++++++++++++ src/ScriptCs/Command/ScriptExecuteCommand.cs | 15 ++--- src/ScriptCs/ScriptCs.csproj | 1 + src/ScriptCs/ScriptCsArgs.cs | 3 + 11 files changed, 208 insertions(+), 119 deletions(-) create mode 100644 src/ScriptCs/Command/RestoreCommand.cs diff --git a/src/ScriptCs.Core/Package/PackageInstaller.cs b/src/ScriptCs.Core/Package/PackageInstaller.cs index a7e842a2..d751b925 100644 --- a/src/ScriptCs.Core/Package/PackageInstaller.cs +++ b/src/ScriptCs.Core/Package/PackageInstaller.cs @@ -25,19 +25,16 @@ public void InstallPackages(IEnumerable packageIds, bool allo { packageInstalled("Nothing to install."); } + return; } - var successful = true; - foreach (var packageId in packageIds) - { - var result = _installer.InstallPackage(packageId, allowPreRelease, packageInstalled); - successful = successful && result; - } + var successful = packageIds.Select(packageId => _installer.InstallPackage(packageId, allowPreRelease, packageInstalled)) + .Aggregate(true, (current, result) => current && result); if (packageInstalled != null && packageIds.Count() > 1) { - packageInstalled(successful ? "Installation successful" : "Installation unsuccessful"); + packageInstalled(successful ? "Installation successful." : "Installation unsuccessful."); } } } diff --git a/src/ScriptCs.Core/PackageAssemblyResolver.cs b/src/ScriptCs.Core/PackageAssemblyResolver.cs index f2279ac7..ee9d9f39 100644 --- a/src/ScriptCs.Core/PackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/PackageAssemblyResolver.cs @@ -10,8 +10,10 @@ namespace ScriptCs public class PackageAssemblyResolver : IPackageAssemblyResolver { private readonly IFileSystem _fileSystem; + private readonly IPackageContainer _packageContainer; - private IEnumerable _topLevelPackages; + + private List _topLevelPackages; public PackageAssemblyResolver(IFileSystem fileSystem, IPackageContainer packageContainer) { @@ -22,7 +24,8 @@ public PackageAssemblyResolver(IFileSystem fileSystem, IPackageContainer package public IEnumerable GetPackages(string workingDirectory) { var packageFile = Path.Combine(workingDirectory, Constants.PackagesFile); - var packages = _packageContainer.FindReferences(packageFile); + var packages = _packageContainer.FindReferences(packageFile).ToList(); + _topLevelPackages = packages; return packages; @@ -30,11 +33,8 @@ public IEnumerable GetPackages(string workingDirectory) public IEnumerable GetAssemblyNames(string workingDirectory, Action outputCallback = null) { - var packages = GetPackages(workingDirectory); - if (!packages.Any()) - { - return Enumerable.Empty(); - } + var packages = GetPackages(workingDirectory).ToList(); + if (!packages.Any()) return Enumerable.Empty(); var packageFile = Path.Combine(workingDirectory, Constants.PackagesFile); var packageDir = Path.Combine(workingDirectory, Constants.PackagesFolder); @@ -45,7 +45,10 @@ public IEnumerable GetAssemblyNames(string workingDirectory, Action 0) - throw new MissingAssemblyException(string.Format("Missing: {0}", string.Join(",", missingAssemblies.Select(i => i.PackageId + " " + i.FrameworkName.FullName)))); + { + var missingAssembliesString = string.Join(",", missingAssemblies.Select(i => i.PackageId + " " + i.FrameworkName.FullName)); + throw new MissingAssemblyException(string.Format("Missing: {0}", missingAssembliesString)); + } return foundAssemblyPaths; } @@ -62,6 +65,7 @@ private void LoadFiles(string packageDir, IEnumerable package { outputCallback("Cannot find: " + packageRef.PackageId + " " + packageRef.Version); } + continue; } @@ -74,29 +78,30 @@ private void LoadFiles(string packageDir, IEnumerable package outputCallback("Cannot find binaries for " + packageRef.FrameworkName + " in: " + packageRef.PackageId + " " + packageRef.Version); } + continue; } - foreach (var packageFile in compatibleFiles) + var compatibleFilePaths = compatibleFiles.Select(packageFile => Path.Combine(packageDir, nugetPackage.FullName, packageFile)); + + foreach (var path in compatibleFilePaths) { - var path = Path.Combine(packageDir, nugetPackage.FullName, packageFile); - if (!foundAssemblies.Contains(path)) + if (foundAssemblies.Contains(path)) continue; + + foundAssemblies.Add(path); + if (outputCallback != null) { - foundAssemblies.Add(path); - if (outputCallback != null) - { - outputCallback("Found: " + path); - } + outputCallback("Found: " + path); } } - if (nugetPackage.Dependencies != null && nugetPackage.Dependencies.Any() && strictLoad) - { - LoadFiles(packageDir, - nugetPackage.Dependencies.Where(i => _topLevelPackages.All(x => x.PackageId != i.Id)).Select( - i => new PackageReference(i.Id, i.FrameworkName, i.Version)), ref missingAssemblies, - ref foundAssemblies, true, outputCallback); - } + if (nugetPackage.Dependencies == null || !nugetPackage.Dependencies.Any() || !strictLoad) continue; + + var dependencyReferences = nugetPackage.Dependencies + .Where(i => _topLevelPackages.All(x => x.PackageId != i.Id)) + .Select(i => new PackageReference(i.Id, i.FrameworkName, i.Version)); + + LoadFiles(packageDir, dependencyReferences, ref missingAssemblies, ref foundAssemblies, true, outputCallback); } } } diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 1ccc1d26..e7743665 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using ScriptCs.Contracts; @@ -8,7 +9,9 @@ namespace ScriptCs public class ScriptExecutor : IScriptExecutor { private readonly IFileSystem _fileSystem; + private readonly IFilePreProcessor _filePreProcessor; + private readonly IScriptEngine _scriptEngine; public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) @@ -21,47 +24,18 @@ public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) { var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); - var files = PrepareBinFolder(paths, bin); - - var references = new List(); - references.Add("System"); - references.Add("System.Core"); - references.AddRange(files); - - _scriptEngine.BaseDirectory = bin; - - var scriptPackSession = new ScriptPackSession(scriptPacks); - scriptPackSession.InitializePacks(); - - var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); - var code = _filePreProcessor.ProcessFile(path); - - _scriptEngine.Execute( - code: code, - references: references, - scriptPackSession: scriptPackSession); - scriptPackSession.TerminatePacks(); - } - - private IEnumerable PrepareBinFolder(IEnumerable paths, string bin) - { - var files = new List(); + var references = new List { "System", "System.Core" }.Union(paths); - if (!_fileSystem.DirectoryExists(bin)) - _fileSystem.CreateDirectory(bin); + _scriptEngine.BaseDirectory = bin; - foreach (var file in paths) + using (var scriptPackSession = new ScriptPackSession(scriptPacks)) { - var destFile = Path.Combine(bin, Path.GetFileName(file)); - var sourceFileLastWriteTime = _fileSystem.GetLastWriteTime(file); - var destFileLastWriteTime = _fileSystem.GetLastWriteTime(destFile); - if (sourceFileLastWriteTime != destFileLastWriteTime) - _fileSystem.Copy(file, destFile, true); - files.Add(destFile); - } + var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); + var code = _filePreProcessor.ProcessFile(path); - return files; + _scriptEngine.Execute(code, references, scriptPackSession); + } } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptPackSession.cs b/src/ScriptCs.Core/ScriptPackSession.cs index f729c401..3c72b752 100644 --- a/src/ScriptCs.Core/ScriptPackSession.cs +++ b/src/ScriptCs.Core/ScriptPackSession.cs @@ -5,12 +5,12 @@ namespace ScriptCs { - public class ScriptPackSession : IScriptPackSession + public class ScriptPackSession : IScriptPackSession, IDisposable { private readonly IEnumerable _scriptPacks; - private IList _references; - private IList _namespaces; + private readonly IList _references; + private readonly IList _namespaces; public ScriptPackSession(IEnumerable scriptPacks) { @@ -18,6 +18,8 @@ public ScriptPackSession(IEnumerable scriptPacks) _references = new List(); _namespaces = new List(); + + InitializePacks(); } public IEnumerable ScriptPacks @@ -35,30 +37,44 @@ public IEnumerable Namespaces get { return _namespaces; } } - public void InitializePacks() + void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) { - foreach (var s in _scriptPacks) - { - s.Initialize(this); - } + _references.Add(assemblyDisplayNameOrPath); } - public void TerminatePacks() + void IScriptPackSession.ImportNamespace(string @namespace) { - foreach (var s in _scriptPacks) + _namespaces.Add(@namespace); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) { - s.Terminate(); + TerminatePacks(); } } - void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) + private void InitializePacks() { - _references.Add(assemblyDisplayNameOrPath); + foreach (var s in _scriptPacks) + { + s.Initialize(this); + } } - void IScriptPackSession.ImportNamespace(string @namespace) + private void TerminatePacks() { - _namespaces.Add(@namespace); + foreach (var s in _scriptPacks) + { + s.Terminate(); + } } } } diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 7733a0df..d94e81d2 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -13,14 +13,26 @@ public ICommand CreateCommand(ScriptCsArgs args) { if (args.ScriptName != null) { - return new ScriptExecuteCommand(args.ScriptName, _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver); + return new ScriptExecuteCommand( + args.ScriptName, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.Executor, + _scriptServiceRoot.ScriptPackResolver); } if (args.Install != null) { - return new InstallCommand(args.Install, args.AllowPreReleaseFlag, _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.PackageInstaller); + return new InstallCommand( + args.Install, + args.AllowPreReleaseFlag, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.PackageInstaller); + } + + if (args.Restore != null) + { + return new RestoreCommand(_scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver); } return new InvalidCommand(); diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index 10e25187..59e5943b 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -1,16 +1,12 @@ namespace ScriptCs.Command { - public interface IScriptCommand : ICommand - { - } + public interface IScriptCommand : ICommand { } - public interface IInstallCommand : ICommand - { - } + public interface IRestoreCommand : ICommand { } - public interface IInvalidCommand : ICommand - { - } + public interface IInstallCommand : ICommand { } + + public interface IInvalidCommand : ICommand { } public interface ICommand { diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index b7af645f..6cd3acdd 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -1,19 +1,29 @@ using System; using System.Collections.Generic; using System.Runtime.Versioning; + using ScriptCs.Package; namespace ScriptCs.Command { - internal class InstallCommand : IInstallCommand + internal class InstallCommand : RestoreCommand, IInstallCommand { private readonly string _name; + private readonly bool _allowPre; + private readonly IFileSystem _fileSystem; + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + private readonly IPackageInstaller _packageInstaller; - public InstallCommand(string name, bool allowPre, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IPackageInstaller packageInstaller) + public InstallCommand( + string name, + bool allowPre, + IFileSystem fileSystem, + IPackageAssemblyResolver packageAssemblyResolver, + IPackageInstaller packageInstaller) : base(fileSystem, packageAssemblyResolver) { _name = name; _allowPre = allowPre; @@ -22,31 +32,41 @@ public InstallCommand(string name, bool allowPre, IFileSystem fileSystem, IPacka _packageInstaller = packageInstaller; } - public int Execute() + public override int Execute() { + Console.WriteLine("Installing packages..."); + var workingDirectory = _fileSystem.CurrentDirectory; - IEnumerable pkgs; + var packages = GetPackages(workingDirectory); - if (string.IsNullOrWhiteSpace(_name)) + try { - pkgs = _packageAssemblyResolver.GetPackages(workingDirectory); + _packageInstaller.InstallPackages(packages, _allowPre, Console.WriteLine); + + Console.WriteLine("Installation completed successfully."); + return base.Execute(); } - else + catch (Exception e) { - pkgs = new[] { new PackageReference(_name, new FrameworkName(".NETFramework,Version=v4.0"), new Version()) }; + Console.WriteLine("Installation failed: {0}.", e.Message); + return -1; } + } - try - { - _packageInstaller.InstallPackages(pkgs, _allowPre, msg => Console.WriteLine(msg)); - return 0; - } - catch (Exception e) + private IEnumerable GetPackages(string workingDirectory) + { + if (string.IsNullOrWhiteSpace(_name)) { - Console.WriteLine("Installation failed"); - Console.WriteLine(e.Message); - return -1; + var packages = _packageAssemblyResolver.GetPackages(workingDirectory); + foreach (var packageReference in packages) + { + yield return packageReference; + } + + yield break; } + + yield return new PackageReference(_name, new FrameworkName(".NETFramework,Version=v4.0"), new Version()); } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/RestoreCommand.cs b/src/ScriptCs/Command/RestoreCommand.cs new file mode 100644 index 00000000..5535d78d --- /dev/null +++ b/src/ScriptCs/Command/RestoreCommand.cs @@ -0,0 +1,66 @@ +using System; +using System.IO; + +namespace ScriptCs.Command +{ + public class RestoreCommand : IRestoreCommand + { + private readonly IFileSystem _fileSystem; + + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + + public RestoreCommand(IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver) + { + _fileSystem = fileSystem; + _packageAssemblyResolver = packageAssemblyResolver; + } + + public virtual int Execute() + { + Console.WriteLine("Moving assemblies to bin folder..."); + + var binFolder = Path.Combine(_fileSystem.CurrentDirectory, "bin"); + + try + { + if (!_fileSystem.DirectoryExists(binFolder)) + _fileSystem.CreateDirectory(binFolder); + + var packages = _packageAssemblyResolver.GetAssemblyNames(_fileSystem.CurrentDirectory); + foreach (var package in packages) + { + MoveFile(package, binFolder); + } + + Console.WriteLine("Restore completed successfully."); + return 0; + } + catch (Exception e) + { + Console.WriteLine("Restore failed: {0}.", e.Message); + return -1; + } + } + + private void MoveFile(string package, string binFolder) + { + var packageFileName = Path.GetFileName(package); + if (packageFileName == null) return; + + var destFile = Path.Combine(binFolder, packageFileName); + + var sourceFileLastWriteTime = _fileSystem.GetLastWriteTime(package); + var destFileLastWriteTime = _fileSystem.GetLastWriteTime(destFile); + + if (sourceFileLastWriteTime == destFileLastWriteTime) + { + Console.WriteLine("Skipped {0}.", packageFileName); + return; + } + + _fileSystem.Copy(package, destFile, true); + + Console.WriteLine("Moved {0}.", packageFileName); + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/ScriptExecuteCommand.cs b/src/ScriptCs/Command/ScriptExecuteCommand.cs index 5214e88e..144c7153 100644 --- a/src/ScriptCs/Command/ScriptExecuteCommand.cs +++ b/src/ScriptCs/Command/ScriptExecuteCommand.cs @@ -1,7 +1,6 @@ using System; -using System.ComponentModel.Composition.Hosting; +using System.IO; using System.Linq; -using ScriptCs.Exceptions; namespace ScriptCs.Command { @@ -9,15 +8,13 @@ internal class ScriptExecuteCommand : IScriptCommand { private readonly string _script; private readonly IFileSystem _fileSystem; - private readonly IPackageAssemblyResolver _packageAssemblyResolver; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - public ScriptExecuteCommand(string script, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver) + public ScriptExecuteCommand(string script, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver) { _script = script; _fileSystem = fileSystem; - _packageAssemblyResolver = packageAssemblyResolver; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; } @@ -27,13 +24,15 @@ public int Execute() try { var workingDirectory = _fileSystem.GetWorkingDirectory(_script); - var paths = _packageAssemblyResolver.GetAssemblyNames(workingDirectory).ToList(); - foreach (var path in paths) + var binFolder = Path.Combine(workingDirectory, "bin"); + + var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll").ToList(); + foreach (var path in assemblyPaths.Select(Path.GetFileName)) { Console.WriteLine("Found assembly reference: " + path); } - _scriptExecutor.Execute(_script, paths, _scriptPackResolver.GetPacks()); + _scriptExecutor.Execute(_script, assemblyPaths, _scriptPackResolver.GetPacks()); return 0; } catch (Exception ex) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index d80588c3..e904e26d 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -45,6 +45,7 @@ + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 5b7fe5fb..b6c9db78 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -15,6 +15,9 @@ public class ScriptCsArgs [ArgShortcut("install")] public string Install { get; set; } + [ArgShortcut("restore")] + public string Restore { get; set; } + [ArgShortcut("pre")] public bool AllowPreReleaseFlag { get; set; } From aa207a43273ed98f9ab09c883d46a31c868c0099 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 22 Mar 2013 18:05:11 +0100 Subject: [PATCH 0145/1224] Fixed failing tests --- src/ScriptCs/Command/ScriptExecuteCommand.cs | 23 +++- .../PackageInstallerTests.cs | 4 +- .../ScriptExecutorTests.cs | 101 +-------------- .../RoslynScriptDebuggerEngine.cs | 4 +- test/ScriptCs.Tests/RestoreCommandTests.cs | 115 ++++++++++++++++++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 + 6 files changed, 140 insertions(+), 108 deletions(-) create mode 100644 test/ScriptCs.Tests/RestoreCommandTests.cs diff --git a/src/ScriptCs/Command/ScriptExecuteCommand.cs b/src/ScriptCs/Command/ScriptExecuteCommand.cs index 144c7153..7841895f 100644 --- a/src/ScriptCs/Command/ScriptExecuteCommand.cs +++ b/src/ScriptCs/Command/ScriptExecuteCommand.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; @@ -23,13 +24,12 @@ public int Execute() { try { - var workingDirectory = _fileSystem.GetWorkingDirectory(_script); - var binFolder = Path.Combine(workingDirectory, "bin"); + var assemblyPaths = Enumerable.Empty(); - var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll").ToList(); - foreach (var path in assemblyPaths.Select(Path.GetFileName)) + var workingDirectory = _fileSystem.GetWorkingDirectory(_script); + if (workingDirectory != null) { - Console.WriteLine("Found assembly reference: " + path); + assemblyPaths = GetAssemblyPaths(workingDirectory); } _scriptExecutor.Execute(_script, assemblyPaths, _scriptPackResolver.GetPacks()); @@ -41,5 +41,18 @@ public int Execute() return -1; } } + + private IEnumerable GetAssemblyPaths(string workingDirectory) + { + var binFolder = Path.Combine(workingDirectory, "bin"); + + var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll").ToList(); + foreach (var path in assemblyPaths.Select(Path.GetFileName)) + { + Console.WriteLine("Found assembly reference: " + path); + } + + return assemblyPaths; + } } } \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/PackageInstallerTests.cs b/test/ScriptCs.Core.Tests/PackageInstallerTests.cs index d3739c22..dd18ab8a 100644 --- a/test/ScriptCs.Core.Tests/PackageInstallerTests.cs +++ b/test/ScriptCs.Core.Tests/PackageInstallerTests.cs @@ -66,7 +66,7 @@ public void ShouldShowErrorIfOneOfPackagesFail() provider.Verify(i => i.InstallPackage(It.IsAny(), It.IsAny(), It.IsAny>()), Times.Exactly(3)); callbacks.Count.ShouldEqual(1); - callbacks.Count(x => x.EndsWith("unsuccessful")).ShouldEqual(1); + callbacks.Count(x => x.EndsWith("unsuccessful.")).ShouldEqual(1); } [Fact] @@ -88,7 +88,7 @@ public void ShouldShowSuccessIfNoneOfPackagesFail() installer.InstallPackages(references, true, msg => callbacks.Add(msg)); callbacks.Count.ShouldEqual(1); - callbacks.Count(x => x.EndsWith("successful")).ShouldEqual(1); + callbacks.Count(x => x.EndsWith("successful.")).ShouldEqual(1); } } } diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index b05ffdcf..def0bc7b 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -95,35 +95,6 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() expectedBaseDirectory.ShouldEqual(scriptEngine.Object.BaseDirectory); } - [Fact] - public void ShouldCreateCurrentDirectoryIfItDoesNotExist() - { - // arrange - var fileSystem = new Mock(); - - var currentDirectory = @"C:\"; - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - - var binDirectory = Path.Combine(currentDirectory, "bin"); - - fileSystem.Setup(fs => fs.DirectoryExists(binDirectory)).Returns(false).Verifiable(); - fileSystem.Setup(fs => fs.CreateDirectory(binDirectory)).Verifiable(); - - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem); - - var scriptName = "script.csx"; - var paths = new string[0]; - IEnumerable recipes = Enumerable.Empty(); - - // act - scriptExecutor.Execute(scriptName, paths, recipes); - - // assert - fileSystem.Verify(fs => fs.DirectoryExists(binDirectory), Times.Once()); - fileSystem.Verify(fs => fs.CreateDirectory(binDirectory), Times.Once()); - } - [Fact] public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked() { @@ -160,72 +131,6 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut } - [Fact] - public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() - { - // arrange - var fileSystem = new Mock(); - - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem); - - var currentDirectory = @"C:\"; - var sourceFilePath = Path.Combine(@"C:\fileDir", "fileName.cs"); - var destinationFilePath = Path.Combine(currentDirectory, @"bin\fileName.cs"); - - var scriptName = "script.csx"; - var paths = new string[] { sourceFilePath }; - - var sourceWriteTime = new DateTime(2013, 3, 7); - var destinatioWriteTime = new DateTime(2013, 3, 8); - - fileSystem.Setup(fs => fs.GetWorkingDirectory(scriptName)).Returns(currentDirectory); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); - fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); - fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); - - // act - scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); - - // assert - fileSystem.Verify(fs => fs.Copy(sourceFilePath, destinationFilePath, true), Times.Once()); - fileSystem.Verify(fs => fs.GetLastWriteTime(sourceFilePath), Times.Once()); - fileSystem.Verify(fs => fs.GetLastWriteTime(destinationFilePath), Times.Once()); - } - - [Fact] - public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBin() - { - // arrange - var fileSystem = new Mock(); - - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem); - - var currentDirectory = @"C:\"; - var sourceFilePath = Path.Combine(@"C:\fileDir", "fileName.cs"); - var destinationFilePath = Path.Combine(currentDirectory, @"bin\fileName.cs"); - - var scriptName = "script.csx"; - var paths = new string[] { sourceFilePath }; - - var sourceWriteTime = new DateTime(2013, 3, 7); - var destinatioWriteTime = sourceWriteTime; - - fileSystem.Setup(fs => fs.GetWorkingDirectory(scriptName)).Returns(currentDirectory); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); - fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); - fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); - - // act - scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); - - // assert - fileSystem.Verify(fs => fs.Copy(sourceFilePath, destinationFilePath, true), Times.Never()); - fileSystem.Verify(fs => fs.GetLastWriteTime(sourceFilePath), Times.Once()); - fileSystem.Verify(fs => fs.GetLastWriteTime(destinationFilePath), Times.Once()); - } - [Fact] public void ShouldAddReferenceToEachDestinationFile() { @@ -236,10 +141,6 @@ public void ShouldAddReferenceToEachDestinationFile() var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); var currentDirectory = @"C:\"; - var sourceFilePath1 = Path.Combine(@"C:\fileDir", "fileName1.cs"); - var sourceFilePath2 = Path.Combine(@"C:\fileDir", "fileName2.cs"); - var sourceFilePath3 = Path.Combine(@"C:\fileDir", "fileName3.cs"); - var sourceFilePath4 = Path.Combine(@"C:\fileDir", "fileName4.cs"); var destinationFilePath1 = Path.Combine(currentDirectory, @"bin\fileName1.cs"); var destinationFilePath2 = Path.Combine(currentDirectory, @"bin\fileName2.cs"); var destinationFilePath3 = Path.Combine(currentDirectory, @"bin\fileName3.cs"); @@ -247,7 +148,7 @@ public void ShouldAddReferenceToEachDestinationFile() var scriptName = "script.csx"; - var paths = new string[] { sourceFilePath1, sourceFilePath2, sourceFilePath3, sourceFilePath4 }; + var paths = new string[] { destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs index e418cf92..c15b60b4 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs @@ -37,7 +37,9 @@ public void ShouldThrowExceptionThrownByScriptWhenErrorOccurs() () => scriptEngine.Execute( code, Enumerable.Empty(), new ScriptPackSession(Enumerable.Empty()))); - + + Console.WriteLine(exception.Message); + exception.Message.ShouldContain("line 2"); exception.Message.ShouldContain("Exception Message: InvalidOperationExceptionMessage."); } diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs new file mode 100644 index 00000000..c321fa1a --- /dev/null +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Moq; + +using ScriptCs.Command; +using ScriptCs.Contracts; + +using Xunit; + +namespace ScriptCs.Tests +{ + public class RestoreCommandTests + { + public class TheExecuteMethod + { + [Fact] + public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBin() + { + // arrange + var fileSystem = new Mock(); + var packageAssemblyResolver = new Mock(); + + var command = new RestoreCommand(fileSystem.Object, packageAssemblyResolver.Object); + + var currentDirectory = @"C:\fileDir"; + + var sourceFilePath = Path.Combine(@"C:\fileDir", "fileName.cs"); + var sourceWriteTime = new DateTime(2013, 3, 7); + + var destinationFilePath = Path.Combine(currentDirectory, @"C:\fileDir\bin\fileName.cs"); + var destinatioWriteTime = sourceWriteTime; + + packageAssemblyResolver.Setup(par => par.GetAssemblyNames(currentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); + + fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + + fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); + fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); + + fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); + + // act + command.Execute(); + + // assert + fileSystem.Verify(fs => fs.Copy(sourceFilePath, destinationFilePath, true), Times.Never()); + fileSystem.Verify(fs => fs.GetLastWriteTime(sourceFilePath), Times.Once()); + fileSystem.Verify(fs => fs.GetLastWriteTime(destinationFilePath), Times.Once()); + } + + [Fact] + public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() + { + // arrange + var fileSystem = new Mock(); + var packageAssemblyResolver = new Mock(); + + var command = new RestoreCommand(fileSystem.Object, packageAssemblyResolver.Object); + + var currentDirectory = @"C:\fileDir"; + + var sourceFilePath = Path.Combine(@"C:\fileDir", "fileName.cs"); + var sourceWriteTime = new DateTime(2013, 3, 7); + + var destinationFilePath = Path.Combine(currentDirectory, @"C:\fileDir\bin\fileName.cs"); + var destinatioWriteTime = new DateTime(2013, 3, 8); + + packageAssemblyResolver.Setup(par => par.GetAssemblyNames(currentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); + + fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); + fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); + fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); + + // act + command.Execute(); + + // assert + fileSystem.Verify(fs => fs.Copy(sourceFilePath, destinationFilePath, true), Times.Once()); + fileSystem.Verify(fs => fs.GetLastWriteTime(sourceFilePath), Times.Once()); + fileSystem.Verify(fs => fs.GetLastWriteTime(destinationFilePath), Times.Once()); + } + + [Fact] + public void ShouldCreateCurrentDirectoryIfItDoesNotExist() + { + // arrange + var fileSystem = new Mock(); + + var currentDirectory = @"C:\"; + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); + fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + + var binDirectory = Path.Combine(currentDirectory, "bin"); + + fileSystem.Setup(fs => fs.DirectoryExists(binDirectory)).Returns(false).Verifiable(); + fileSystem.Setup(fs => fs.CreateDirectory(binDirectory)).Verifiable(); + + var packageAssemblyResolver = new Mock(); + + var command = new RestoreCommand(fileSystem.Object, packageAssemblyResolver.Object); + + // act + command.Execute(); + + // assert + fileSystem.Verify(fs => fs.DirectoryExists(binDirectory), Times.Once()); + fileSystem.Verify(fs => fs.CreateDirectory(binDirectory), Times.Once()); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 98bf82e1..5f6edf1a 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -39,6 +39,7 @@ + From e31a740305f721affe0e2052820b43519296ca1d Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 22 Mar 2013 22:32:39 +0100 Subject: [PATCH 0146/1224] Minor test refactoring --- test/ScriptCs.Tests/CommandFactoryTests.cs | 11 ++ test/ScriptCs.Tests/RestoreCommandTests.cs | 120 +++++++++++---------- 2 files changed, 74 insertions(+), 57 deletions(-) diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 031dacfc..32992e3f 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -70,6 +70,17 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() result.ShouldImplement(); } + [Fact] + public void ShouldRestoreWhenRestoreIsPassed() + { + var args = new ScriptCsArgs { Restore = "" }; + + var factory = new CommandFactory(CreateRoot()); + var result = factory.CreateCommand(args); + + result.ShouldImplement(); + } + [Fact] public void ShouldReturnInvalidWhenNoNameOrInstallSet() { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index c321fa1a..4e687221 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -2,11 +2,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.Versioning; using Moq; using ScriptCs.Command; -using ScriptCs.Contracts; +using ScriptCs.Package; using Xunit; @@ -19,96 +20,101 @@ public class TheExecuteMethod [Fact] public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBin() { - // arrange - var fileSystem = new Mock(); - var packageAssemblyResolver = new Mock(); + var args = new ScriptCsArgs { Restore = "" }; - var command = new RestoreCommand(fileSystem.Object, packageAssemblyResolver.Object); + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); - var currentDirectory = @"C:\fileDir"; + const string CurrentDirectory = @"C:\"; - var sourceFilePath = Path.Combine(@"C:\fileDir", "fileName.cs"); + var sourceFilePath = Path.Combine(CurrentDirectory, "fileName.cs"); var sourceWriteTime = new DateTime(2013, 3, 7); - var destinationFilePath = Path.Combine(currentDirectory, @"C:\fileDir\bin\fileName.cs"); - var destinatioWriteTime = sourceWriteTime; + var destFilePath = Path.Combine(CurrentDirectory, "bin", "fileName.cs"); + var destWriteTime = sourceWriteTime; - packageAssemblyResolver.Setup(par => par.GetAssemblyNames(currentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); + fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); - fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); - fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); - fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); + result.Execute(); - // act - command.Execute(); - - // assert - fileSystem.Verify(fs => fs.Copy(sourceFilePath, destinationFilePath, true), Times.Never()); - fileSystem.Verify(fs => fs.GetLastWriteTime(sourceFilePath), Times.Once()); - fileSystem.Verify(fs => fs.GetLastWriteTime(destinationFilePath), Times.Once()); + fs.Verify(x => x.Copy(sourceFilePath, destFilePath, true), Times.Never()); + fs.Verify(x => x.GetLastWriteTime(sourceFilePath), Times.Once()); + fs.Verify(x => x.GetLastWriteTime(destFilePath), Times.Once()); } [Fact] public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() { - // arrange - var fileSystem = new Mock(); - var packageAssemblyResolver = new Mock(); + var args = new ScriptCsArgs { Restore = "" }; - var command = new RestoreCommand(fileSystem.Object, packageAssemblyResolver.Object); + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); - var currentDirectory = @"C:\fileDir"; + const string CurrentDirectory = @"C:\"; - var sourceFilePath = Path.Combine(@"C:\fileDir", "fileName.cs"); + var sourceFilePath = Path.Combine(CurrentDirectory, "fileName.cs"); var sourceWriteTime = new DateTime(2013, 3, 7); - var destinationFilePath = Path.Combine(currentDirectory, @"C:\fileDir\bin\fileName.cs"); - var destinatioWriteTime = new DateTime(2013, 3, 8); + var destFilePath = Path.Combine(CurrentDirectory, "bin", "fileName.cs"); + var destWriteTime = new DateTime(2013, 2, 7); + + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); + fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); - packageAssemblyResolver.Setup(par => par.GetAssemblyNames(currentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); + resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - fileSystem.Setup(fs => fs.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); - fileSystem.Setup(fs => fs.GetLastWriteTime(destinationFilePath)).Returns(destinatioWriteTime).Verifiable(); - fileSystem.Setup(fs => fs.Copy(sourceFilePath, destinationFilePath, true)); + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); - // act - command.Execute(); + result.Execute(); - // assert - fileSystem.Verify(fs => fs.Copy(sourceFilePath, destinationFilePath, true), Times.Once()); - fileSystem.Verify(fs => fs.GetLastWriteTime(sourceFilePath), Times.Once()); - fileSystem.Verify(fs => fs.GetLastWriteTime(destinationFilePath), Times.Once()); + fs.Verify(x => x.Copy(sourceFilePath, destFilePath, true), Times.Once()); + fs.Verify(x => x.GetLastWriteTime(sourceFilePath), Times.Once()); + fs.Verify(x => x.GetLastWriteTime(destFilePath), Times.Once()); } [Fact] - public void ShouldCreateCurrentDirectoryIfItDoesNotExist() + public void ShouldCreateBinFolderIfItDoesNotExist() { - // arrange - var fileSystem = new Mock(); - - var currentDirectory = @"C:\"; - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + var args = new ScriptCsArgs { Restore = "", }; - var binDirectory = Path.Combine(currentDirectory, "bin"); + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); - fileSystem.Setup(fs => fs.DirectoryExists(binDirectory)).Returns(false).Verifiable(); - fileSystem.Setup(fs => fs.CreateDirectory(binDirectory)).Verifiable(); + const string CurrentDirectory = @"C:\"; + const string BinFolder = @"C:\bin"; - var packageAssemblyResolver = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fs.Setup(x => x.DirectoryExists(BinFolder)).Returns(false).Verifiable(); + fs.Setup(x => x.CreateDirectory(BinFolder)).Verifiable(); - var command = new RestoreCommand(fileSystem.Object, packageAssemblyResolver.Object); + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); - // act - command.Execute(); + result.Execute(); - // assert - fileSystem.Verify(fs => fs.DirectoryExists(binDirectory), Times.Once()); - fileSystem.Verify(fs => fs.CreateDirectory(binDirectory), Times.Once()); + fs.Verify(x => x.DirectoryExists(BinFolder), Times.Once()); + fs.Verify(x => x.CreateDirectory(BinFolder), Times.Once()); } } } From 305d7476264cdbdde5b94c80d2f507f0a3579b17 Mon Sep 17 00:00:00 2001 From: Danielle Boldt Date: Fri, 22 Mar 2013 20:54:16 -0400 Subject: [PATCH 0147/1224] Added version information Version is now displayed whenever ScriptCs is launched. --- src/ScriptCs/Program.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 4a3dd239..7d3e3f4c 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,5 +1,6 @@ using PowerArgs; using ScriptCs.Command; +using System; namespace ScriptCs { @@ -7,6 +8,7 @@ internal class Program { private static int Main(string[] args) { + Console.WriteLine(string.Format("ScriptCs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version)); var commandArgs = Args.Parse(args); var debug = commandArgs.DebugFlag; From e553a92215588991e4a7a24384cfcd5f3980d068 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 23 Mar 2013 03:11:26 +0100 Subject: [PATCH 0148/1224] Changed -restore flag too bool and removed IDisposable on ScriptPackSession --- src/ScriptCs.Core/ScriptExecutor.cs | 14 ++++--- src/ScriptCs.Core/ScriptPackSession.cs | 48 ++++++++-------------- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/ScriptCsArgs.cs | 2 +- test/ScriptCs.Tests/CommandFactoryTests.cs | 2 +- test/ScriptCs.Tests/RestoreCommandTests.cs | 9 ++-- 6 files changed, 30 insertions(+), 47 deletions(-) diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index e7743665..cffda641 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -29,13 +29,15 @@ public void Execute(string script, IEnumerable paths, IEnumerable _scriptPacks; - private readonly IList _references; - private readonly IList _namespaces; + private IList _references; + private IList _namespaces; public ScriptPackSession(IEnumerable scriptPacks) { @@ -18,8 +18,6 @@ public ScriptPackSession(IEnumerable scriptPacks) _references = new List(); _namespaces = new List(); - - InitializePacks(); } public IEnumerable ScriptPacks @@ -37,31 +35,7 @@ public IEnumerable Namespaces get { return _namespaces; } } - void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) - { - _references.Add(assemblyDisplayNameOrPath); - } - - void IScriptPackSession.ImportNamespace(string @namespace) - { - _namespaces.Add(@namespace); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - TerminatePacks(); - } - } - - private void InitializePacks() + public void InitializePacks() { foreach (var s in _scriptPacks) { @@ -69,12 +43,22 @@ private void InitializePacks() } } - private void TerminatePacks() + public void TerminatePacks() { foreach (var s in _scriptPacks) { s.Terminate(); } } + + void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) + { + _references.Add(assemblyDisplayNameOrPath); + } + + void IScriptPackSession.ImportNamespace(string @namespace) + { + _namespaces.Add(@namespace); + } } -} +} \ No newline at end of file diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d94e81d2..18147268 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -30,7 +30,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.PackageInstaller); } - if (args.Restore != null) + if (args.Restore) { return new RestoreCommand(_scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver); } diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index b6c9db78..77c0f061 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -16,7 +16,7 @@ public class ScriptCsArgs public string Install { get; set; } [ArgShortcut("restore")] - public string Restore { get; set; } + public bool Restore { get; set; } [ArgShortcut("pre")] public bool AllowPreReleaseFlag { get; set; } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 32992e3f..6a16404a 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -73,7 +73,7 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() [Fact] public void ShouldRestoreWhenRestoreIsPassed() { - var args = new ScriptCsArgs { Restore = "" }; + var args = new ScriptCsArgs { Restore = true }; var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index 4e687221..9ed3864e 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Runtime.Versioning; using Moq; @@ -20,7 +17,7 @@ public class TheExecuteMethod [Fact] public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBin() { - var args = new ScriptCsArgs { Restore = "" }; + var args = new ScriptCsArgs { Restore = true }; var fs = new Mock(); var resolver = new Mock(); @@ -56,7 +53,7 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi [Fact] public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() { - var args = new ScriptCsArgs { Restore = "" }; + var args = new ScriptCsArgs { Restore = true }; var fs = new Mock(); var resolver = new Mock(); @@ -92,7 +89,7 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn [Fact] public void ShouldCreateBinFolderIfItDoesNotExist() { - var args = new ScriptCsArgs { Restore = "", }; + var args = new ScriptCsArgs { Restore = true }; var fs = new Mock(); var resolver = new Mock(); From b36b1b6cd3cdf8526f199a241b1346353867addc Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 24 Mar 2013 22:25:18 +0100 Subject: [PATCH 0149/1224] Added CompositeCommand for combining commands, -restore should now be provided with a script name to restore before executing the script --- src/ScriptCs/Command/CommandFactory.cs | 26 ++++++++++---- src/ScriptCs/Command/CommandResult.cs | 8 +++++ src/ScriptCs/Command/CompositeCommand.cs | 29 ++++++++++++++++ ...cuteCommand.cs => ExecuteScriptCommand.cs} | 10 +++--- src/ScriptCs/Command/ICommand.cs | 11 ++++-- src/ScriptCs/Command/InstallCommand.cs | 10 +++--- src/ScriptCs/Command/InvalidCommand.cs | 4 +-- src/ScriptCs/Command/RestoreCommand.cs | 34 +++++++++++-------- src/ScriptCs/Program.cs | 10 +++++- src/ScriptCs/ScriptCs.csproj | 4 ++- test/ScriptCs.Tests/CommandFactoryTests.cs | 16 ++++++--- ...dTests.cs => ExecuteScriptCommandTests.cs} | 2 +- test/ScriptCs.Tests/InstallCommandTests.cs | 4 +++ test/ScriptCs.Tests/RestoreCommandTests.cs | 15 ++++---- test/ScriptCs.Tests/ScriptCs.Tests.csproj | 2 +- 15 files changed, 136 insertions(+), 49 deletions(-) create mode 100644 src/ScriptCs/Command/CommandResult.cs create mode 100644 src/ScriptCs/Command/CompositeCommand.cs rename src/ScriptCs/Command/{ScriptExecuteCommand.cs => ExecuteScriptCommand.cs} (86%) rename test/ScriptCs.Tests/{ScriptExecuteCommandTests.cs => ExecuteScriptCommandTests.cs} (96%) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 18147268..9323a682 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -13,26 +13,40 @@ public ICommand CreateCommand(ScriptCsArgs args) { if (args.ScriptName != null) { - return new ScriptExecuteCommand( + var executeCommand = new ExecuteScriptCommand( args.ScriptName, _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver); + + if (args.Restore) + { + var restoreCommand = new RestoreCommand( + args.ScriptName, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.PackageAssemblyResolver); + + return new CompositeCommand(restoreCommand, executeCommand); + } + + return executeCommand; } if (args.Install != null) { - return new InstallCommand( + var installCommand = new InstallCommand( args.Install, args.AllowPreReleaseFlag, _scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.PackageInstaller); - } - if (args.Restore) - { - return new RestoreCommand(_scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver); + var restoreCommand = new RestoreCommand( + args.Install, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.PackageAssemblyResolver); + + return new CompositeCommand(installCommand, restoreCommand); } return new InvalidCommand(); diff --git a/src/ScriptCs/Command/CommandResult.cs b/src/ScriptCs/Command/CommandResult.cs new file mode 100644 index 00000000..3b6fbda8 --- /dev/null +++ b/src/ScriptCs/Command/CommandResult.cs @@ -0,0 +1,8 @@ +namespace ScriptCs.Command +{ + public enum CommandResult + { + Success, + Error + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/CompositeCommand.cs b/src/ScriptCs/Command/CompositeCommand.cs new file mode 100644 index 00000000..2c052a80 --- /dev/null +++ b/src/ScriptCs/Command/CompositeCommand.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ScriptCs.Command +{ + public class CompositeCommand : ICompositeCommand + { + public CompositeCommand(params ICommand[] commands) + { + Commands = commands.ToList(); + } + + public List Commands { get; private set; } + + public CommandResult Execute() + { + var result = CommandResult.Success; + foreach (var command in Commands) + { + result = command.Execute(); + + if (result != CommandResult.Success) + return result; + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/ScriptExecuteCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs similarity index 86% rename from src/ScriptCs/Command/ScriptExecuteCommand.cs rename to src/ScriptCs/Command/ExecuteScriptCommand.cs index 7841895f..4803c213 100644 --- a/src/ScriptCs/Command/ScriptExecuteCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -5,14 +5,14 @@ namespace ScriptCs.Command { - internal class ScriptExecuteCommand : IScriptCommand + internal class ExecuteScriptCommand : IScriptCommand { private readonly string _script; private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - public ScriptExecuteCommand(string script, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver) + public ExecuteScriptCommand(string script, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver) { _script = script; _fileSystem = fileSystem; @@ -20,7 +20,7 @@ public ScriptExecuteCommand(string script, IFileSystem fileSystem, IScriptExecut _scriptPackResolver = scriptPackResolver; } - public int Execute() + public CommandResult Execute() { try { @@ -33,12 +33,12 @@ public int Execute() } _scriptExecutor.Execute(_script, assemblyPaths, _scriptPackResolver.GetPacks()); - return 0; + return CommandResult.Success; } catch (Exception ex) { Console.WriteLine(ex.Message); - return -1; + return CommandResult.Error; } } diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index 59e5943b..1d11dfa0 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -1,4 +1,6 @@ -namespace ScriptCs.Command +using System.Collections.Generic; + +namespace ScriptCs.Command { public interface IScriptCommand : ICommand { } @@ -8,8 +10,13 @@ public interface IInstallCommand : ICommand { } public interface IInvalidCommand : ICommand { } + public interface ICompositeCommand : ICommand + { + List Commands { get; } + } + public interface ICommand { - int Execute(); + CommandResult Execute(); } } \ No newline at end of file diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index 6cd3acdd..d88ca79d 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -6,7 +6,7 @@ namespace ScriptCs.Command { - internal class InstallCommand : RestoreCommand, IInstallCommand + internal class InstallCommand : IInstallCommand { private readonly string _name; @@ -23,7 +23,7 @@ public InstallCommand( bool allowPre, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, - IPackageInstaller packageInstaller) : base(fileSystem, packageAssemblyResolver) + IPackageInstaller packageInstaller) { _name = name; _allowPre = allowPre; @@ -32,7 +32,7 @@ public InstallCommand( _packageInstaller = packageInstaller; } - public override int Execute() + public CommandResult Execute() { Console.WriteLine("Installing packages..."); @@ -44,12 +44,12 @@ public override int Execute() _packageInstaller.InstallPackages(packages, _allowPre, Console.WriteLine); Console.WriteLine("Installation completed successfully."); - return base.Execute(); + return CommandResult.Success; } catch (Exception e) { Console.WriteLine("Installation failed: {0}.", e.Message); - return -1; + return CommandResult.Error; } } diff --git a/src/ScriptCs/Command/InvalidCommand.cs b/src/ScriptCs/Command/InvalidCommand.cs index 1cf4fe01..228deace 100644 --- a/src/ScriptCs/Command/InvalidCommand.cs +++ b/src/ScriptCs/Command/InvalidCommand.cs @@ -5,10 +5,10 @@ namespace ScriptCs.Command { internal class InvalidCommand : IInvalidCommand { - public int Execute() + public CommandResult Execute() { Console.WriteLine(ArgUsage.GetUsage()); - return -1; + return CommandResult.Error; } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/RestoreCommand.cs b/src/ScriptCs/Command/RestoreCommand.cs index 5535d78d..2eb3021c 100644 --- a/src/ScriptCs/Command/RestoreCommand.cs +++ b/src/ScriptCs/Command/RestoreCommand.cs @@ -3,64 +3,68 @@ namespace ScriptCs.Command { - public class RestoreCommand : IRestoreCommand + internal class RestoreCommand : IRestoreCommand { + private readonly string _scriptName; + private readonly IFileSystem _fileSystem; private readonly IPackageAssemblyResolver _packageAssemblyResolver; - public RestoreCommand(IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver) + public RestoreCommand(string scriptName, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver) { + _scriptName = scriptName; _fileSystem = fileSystem; _packageAssemblyResolver = packageAssemblyResolver; } - public virtual int Execute() + public CommandResult Execute() { - Console.WriteLine("Moving assemblies to bin folder..."); + Console.WriteLine("Copying assemblies to bin folder..."); - var binFolder = Path.Combine(_fileSystem.CurrentDirectory, "bin"); + var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); + var binFolder = Path.Combine(workingDirectory, "bin"); try { if (!_fileSystem.DirectoryExists(binFolder)) _fileSystem.CreateDirectory(binFolder); - var packages = _packageAssemblyResolver.GetAssemblyNames(_fileSystem.CurrentDirectory); + var packages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); foreach (var package in packages) { - MoveFile(package, binFolder); + CopyFile(package, binFolder); } Console.WriteLine("Restore completed successfully."); - return 0; + return CommandResult.Success; } catch (Exception e) { Console.WriteLine("Restore failed: {0}.", e.Message); - return -1; + return CommandResult.Error; } } - private void MoveFile(string package, string binFolder) + private void CopyFile(string package, string binFolder) { - var packageFileName = Path.GetFileName(package); - if (packageFileName == null) return; + var assemblyFileName = Path.GetFileName(package); + if (assemblyFileName == null) return; - var destFile = Path.Combine(binFolder, packageFileName); + var destFile = Path.Combine(binFolder, assemblyFileName); var sourceFileLastWriteTime = _fileSystem.GetLastWriteTime(package); var destFileLastWriteTime = _fileSystem.GetLastWriteTime(destFile); if (sourceFileLastWriteTime == destFileLastWriteTime) { - Console.WriteLine("Skipped {0}.", packageFileName); + Console.WriteLine("Skipped: {0}.", assemblyFileName); return; } _fileSystem.Copy(package, destFile, true); - Console.WriteLine("Moved {0}.", packageFileName); + Console.WriteLine("Copied: {0}.", assemblyFileName); } } } \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 4a3dd239..02e1a6b9 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -17,7 +17,15 @@ private static int Main(string[] args) var commandFactory = new CommandFactory(scriptServiceRoot); var command = commandFactory.CreateCommand(commandArgs); - return command.Execute(); + var result = command.Execute(); + + switch (result) + { + case CommandResult.Success: + return 0; + default: + return -1; + } } } } \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index e904e26d..aa49af45 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -42,11 +42,13 @@ Properties\CommonVersionInfo.cs + + - + diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 6a16404a..f719e54c 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -35,7 +35,11 @@ public void ShouldInstallWhenInstallFlagIsOn() var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args); - result.ShouldImplement(); + var compositeCommand = result as ICompositeCommand; + compositeCommand.ShouldNotBeNull(); + + (compositeCommand.Commands[0] is IInstallCommand).ShouldBeTrue(); + (compositeCommand.Commands[1] is IRestoreCommand).ShouldBeTrue(); } [Fact] @@ -71,14 +75,18 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() } [Fact] - public void ShouldRestoreWhenRestoreIsPassed() + public void ShouldRestoreWhenBothNameAndRestoreArePassed() { - var args = new ScriptCsArgs { Restore = true }; + var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args); - result.ShouldImplement(); + var compositeCommand = result as ICompositeCommand; + compositeCommand.ShouldNotBeNull(); + + (compositeCommand.Commands[0] is IRestoreCommand).ShouldBeTrue(); + (compositeCommand.Commands[1] is IScriptCommand).ShouldBeTrue(); } [Fact] diff --git a/test/ScriptCs.Tests/ScriptExecuteCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs similarity index 96% rename from test/ScriptCs.Tests/ScriptExecuteCommandTests.cs rename to test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c12aaf07..449496f8 100644 --- a/test/ScriptCs.Tests/ScriptExecuteCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -7,7 +7,7 @@ namespace ScriptCs.Tests { - public class ScriptExecuteCommandTests + public class ExecuteScriptCommandTests { public class ExecuteMethod { diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index aa1c2f4c..6014c127 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -24,6 +24,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() }; var fs = new Mock(); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(@"C:\"); + var resolver = new Mock(); var executor = new Mock(); var scriptpackResolver = new Mock(); @@ -49,6 +51,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() }; var fs = new Mock(); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(@"C:\"); + var resolver = new Mock(); var executor = new Mock(); var scriptpackResolver = new Mock(); diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index 9ed3864e..8d6e9b6c 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -17,7 +17,7 @@ public class TheExecuteMethod [Fact] public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBin() { - var args = new ScriptCsArgs { Restore = true }; + var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; var fs = new Mock(); var resolver = new Mock(); @@ -34,7 +34,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var destFilePath = Path.Combine(CurrentDirectory, "bin", "fileName.cs"); var destWriteTime = sourceWriteTime; - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); @@ -53,7 +54,7 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi [Fact] public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() { - var args = new ScriptCsArgs { Restore = true }; + var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; var fs = new Mock(); var resolver = new Mock(); @@ -70,7 +71,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var destFilePath = Path.Combine(CurrentDirectory, "bin", "fileName.cs"); var destWriteTime = new DateTime(2013, 2, 7); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); @@ -89,7 +91,7 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn [Fact] public void ShouldCreateBinFolderIfItDoesNotExist() { - var args = new ScriptCsArgs { Restore = true }; + var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; var fs = new Mock(); var resolver = new Mock(); @@ -101,7 +103,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.Setup(x => x.DirectoryExists(BinFolder)).Returns(false).Verifiable(); fs.Setup(x => x.CreateDirectory(BinFolder)).Verifiable(); diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 5f6edf1a..733cdd35 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -40,7 +40,7 @@ - + From c9a049097f137980a4fc085bde3f8107f3bc2f60 Mon Sep 17 00:00:00 2001 From: Danielle Boldt Date: Tue, 26 Mar 2013 20:41:58 -0400 Subject: [PATCH 0150/1224] #132 Version flag as a command Specifying -version or -v will output version information. --- src/ScriptCs/Command/ICommand.cs | 4 ++ src/ScriptCs/Command/VersionCommand.cs | 13 +++++ src/ScriptCs/Program.cs | 1 - src/ScriptCs/ScriptCs.csproj | 1 + src/ScriptCs/ScriptCsArgs.cs | 4 ++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 + test/ScriptCs.Tests/VersionCommandTests.cs | 56 ++++++++++++++++++++++ 7 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/ScriptCs/Command/VersionCommand.cs create mode 100644 test/ScriptCs.Tests/VersionCommandTests.cs diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index 10e25187..621fffb3 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -12,6 +12,10 @@ public interface IInvalidCommand : ICommand { } + public interface IVersionCommand : ICommand + { + } + public interface ICommand { int Execute(); diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs new file mode 100644 index 00000000..4d9e57b6 --- /dev/null +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -0,0 +1,13 @@ +using System; + +namespace ScriptCs.Command +{ + internal class VersionCommand : IVersionCommand + { + public int Execute() + { + Console.WriteLine(string.Format("ScriptCs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version)); + return 0; + } + } +} diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 7d3e3f4c..031163b5 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -8,7 +8,6 @@ internal class Program { private static int Main(string[] args) { - Console.WriteLine(string.Format("ScriptCs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version)); var commandArgs = Args.Parse(args); var debug = commandArgs.DebugFlag; diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index d80588c3..8f234eb1 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -46,6 +46,7 @@ + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 5b7fe5fb..9cb4ec9c 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -18,6 +18,10 @@ public class ScriptCsArgs [ArgShortcut("pre")] public bool AllowPreReleaseFlag { get; set; } + [ArgDescription("Outputs version information")] + public bool Version { get; set; } + + public bool IsValid() { return !string.IsNullOrWhiteSpace(ScriptName) || Install != null; diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 98bf82e1..060719cd 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -37,6 +37,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs new file mode 100644 index 00000000..8297d58a --- /dev/null +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -0,0 +1,56 @@ +using Moq; +using ScriptCs.Command; +using ScriptCs.Package; +using System.IO; +using Xunit; + +namespace ScriptCs.Tests +{ + public class VersionCommandTests + { + public class ExecuteMethod + { + + private readonly System.Version _currentVersion; + + System.Text.StringBuilder _outputText; + StringWriter _mockConsole; + TextWriter _actualConsole; + + public ExecuteMethod() + { + _currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + _outputText = new System.Text.StringBuilder(); + _mockConsole = new StringWriter(_outputText); + _actualConsole = System.Console.Out; + System.Console.SetOut(_mockConsole); + } + + [Fact] + public void VersionCommandShouldOutputVersion() + { + var args = new ScriptCsArgs + { + Version = true + }; + + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + // clear the fake console output + _outputText.Clear(); + + result.Execute(); + + Assert.Contains("ScriptCs version " + _currentVersion.ToString(), _outputText.ToString()); + } + } + } +} \ No newline at end of file From 92e561e32f2f080fe6d69a31c0f1e273080d31f4 Mon Sep 17 00:00:00 2001 From: Danielle Boldt Date: Tue, 26 Mar 2013 20:43:15 -0400 Subject: [PATCH 0151/1224] #132 Version flag as a command --- src/ScriptCs/Command/CommandFactory.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 7733a0df..cebca1df 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -23,6 +23,11 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.PackageInstaller); } + if (args.Version) + { + return new VersionCommand(); + } + return new InvalidCommand(); } } From 663127f11f8c5abc9d10dc3f248df5446abe27fb Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 27 Mar 2013 10:14:46 +0100 Subject: [PATCH 0152/1224] ExecuteScriptCommand now creates bin folder if it's missing. Fixes #151 --- src/ScriptCs/Command/ExecuteScriptCommand.cs | 3 ++ .../ExecuteScriptCommandTests.cs | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 4803c213..733f8d18 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -46,6 +46,9 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) { var binFolder = Path.Combine(workingDirectory, "bin"); + if (!_fileSystem.DirectoryExists(binFolder)) + _fileSystem.CreateDirectory(binFolder); + var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll").ToList(); foreach (var path in assemblyPaths.Select(Path.GetFileName)) { diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 449496f8..b888822f 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.IO; + using Moq; using ScriptCs.Command; using ScriptCs.Contracts; @@ -35,6 +37,33 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny>(), It.IsAny>()), Times.Once()); } + + [Fact] + public void ShouldCreateMissingBinFolder() + { + const string WorkingDirectory = @"C:\"; + + var binFolder = Path.Combine(WorkingDirectory, "bin"); + + var args = new ScriptCsArgs { ScriptName = "test.csx" }; + + var fs = new Mock(); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); + fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); + + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + fs.Verify(x => x.CreateDirectory(binFolder), Times.Once()); + } } } } \ No newline at end of file From 5acbd96ef737a56e751a2af75d81e7b725ddbd23 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 27 Mar 2013 16:07:03 +0100 Subject: [PATCH 0153/1224] Fixed failing test after #152 --- test/ScriptCs.Tests/RestoreCommandTests.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index 8d6e9b6c..c2e8015e 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -105,15 +105,17 @@ public void ShouldCreateBinFolderIfItDoesNotExist() fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.Setup(x => x.DirectoryExists(BinFolder)).Returns(false).Verifiable(); - fs.Setup(x => x.CreateDirectory(BinFolder)).Verifiable(); + var binFolderCreated = false; + + fs.Setup(x => x.DirectoryExists(BinFolder)).Returns(() => binFolderCreated).Verifiable(); + fs.Setup(x => x.CreateDirectory(BinFolder)).Callback(() => binFolderCreated = true).Verifiable(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); result.Execute(); - fs.Verify(x => x.DirectoryExists(BinFolder), Times.Once()); + fs.Verify(x => x.DirectoryExists(BinFolder), Times.AtLeastOnce()); fs.Verify(x => x.CreateDirectory(BinFolder), Times.Once()); } } From 6b026d873681cb00c5442538bc74a73c89897133 Mon Sep 17 00:00:00 2001 From: Filip W Date: Wed, 27 Mar 2013 20:30:58 -0400 Subject: [PATCH 0154/1224] changed to constant on "bin" --- src/ScriptCs/Command/RestoreCommand.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ScriptCs/Command/RestoreCommand.cs b/src/ScriptCs/Command/RestoreCommand.cs index 2eb3021c..ea5bd7b2 100644 --- a/src/ScriptCs/Command/RestoreCommand.cs +++ b/src/ScriptCs/Command/RestoreCommand.cs @@ -6,9 +6,7 @@ namespace ScriptCs.Command internal class RestoreCommand : IRestoreCommand { private readonly string _scriptName; - private readonly IFileSystem _fileSystem; - private readonly IPackageAssemblyResolver _packageAssemblyResolver; public RestoreCommand(string scriptName, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver) @@ -23,7 +21,7 @@ public CommandResult Execute() Console.WriteLine("Copying assemblies to bin folder..."); var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); - var binFolder = Path.Combine(workingDirectory, "bin"); + var binFolder = Path.Combine(workingDirectory, Constants.BinFolder); try { From c2e941f0872a5026658b49266c3575fe780f440a Mon Sep 17 00:00:00 2001 From: Filip W Date: Wed, 27 Mar 2013 20:31:49 -0400 Subject: [PATCH 0155/1224] added -clean command. Fixed #142 --- src/ScriptCs.Core/Constants.cs | 1 + src/ScriptCs.Core/FileSystem.cs | 10 ++++ src/ScriptCs.Core/IFileSystem.cs | 4 ++ src/ScriptCs/Command/CleanCommand.cs | 72 ++++++++++++++++++++++++++ src/ScriptCs/Command/CommandFactory.cs | 10 ++++ src/ScriptCs/Command/ICommand.cs | 2 + src/ScriptCs/ScriptCs.csproj | 1 + src/ScriptCs/ScriptCsArgs.cs | 3 ++ 8 files changed, 103 insertions(+) create mode 100644 src/ScriptCs/Command/CleanCommand.cs diff --git a/src/ScriptCs.Core/Constants.cs b/src/ScriptCs.Core/Constants.cs index 9b357007..62a745b0 100644 --- a/src/ScriptCs.Core/Constants.cs +++ b/src/ScriptCs.Core/Constants.cs @@ -5,6 +5,7 @@ public static class Constants public const string PackagesFile = "packages.config"; public const string NugetFile = "nuget.config"; public const string PackagesFolder = "packages"; + public const string BinFolder = "bin"; public const string DefaultRepositoryUrl = "https://nuget.org/api/v2/"; public const string DebugContractName = "Debug"; diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 53a54403..aed7e297 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -26,6 +26,11 @@ public void CreateDirectory(string path) Directory.CreateDirectory(path); } + public void DeleteDirectory(string path) + { + Directory.Delete(path, true); + } + public string ReadFile(string path) { return File.ReadAllText(path); @@ -66,6 +71,11 @@ public bool FileExists(string path) return File.Exists(path); } + public void FileDelete(string path) + { + File.Delete(path); + } + public Stream CreateFileStream(string filePath, FileMode mode) { return new FileStream(filePath, mode); diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index ae3f122d..35ce813f 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -14,6 +14,8 @@ public interface IFileSystem void CreateDirectory(string path); + void DeleteDirectory(string path); + string ReadFile(string path); string[] ReadFileLines(string path); @@ -32,6 +34,8 @@ public interface IFileSystem bool FileExists(string path); + void FileDelete(string path); + Stream CreateFileStream(string filePath, FileMode mode); } } \ No newline at end of file diff --git a/src/ScriptCs/Command/CleanCommand.cs b/src/ScriptCs/Command/CleanCommand.cs new file mode 100644 index 00000000..7ed5d884 --- /dev/null +++ b/src/ScriptCs/Command/CleanCommand.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; +using System.Linq; + +namespace ScriptCs.Command +{ + internal class CleanCommand : ICleanCommand + { + private readonly string _scriptName; + private readonly IFileSystem _fileSystem; + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + + public CleanCommand(string scriptName, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver) + { + _scriptName = scriptName; + _fileSystem = fileSystem; + _packageAssemblyResolver = packageAssemblyResolver; + } + + public CommandResult Execute() + { + Console.WriteLine("Cleaning initiated..."); + + var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); + var binFolder = Path.Combine(workingDirectory, Constants.BinFolder); + var packageFolder = Path.Combine(workingDirectory, Constants.PackagesFolder); + + try + { + if (_fileSystem.DirectoryExists(binFolder)) + { + var packages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); + + foreach (var package in packages) + { + DeleteFile(package, binFolder); + } + + var remaining = _fileSystem.EnumerateFiles(binFolder, "*.*").Any(); + if (!remaining) + { + _fileSystem.DeleteDirectory(binFolder); + } + } + + if (_fileSystem.DirectoryExists(packageFolder)) + _fileSystem.DeleteDirectory(packageFolder); + + Console.WriteLine("Clean completed successfully."); + return CommandResult.Success; + } + catch (Exception e) + { + Console.WriteLine("Clean failed: {0}.", e.Message); + return CommandResult.Error; + } + } + + private void DeleteFile(string package, string binFolder) + { + var assemblyFileName = Path.GetFileName(package); + if (assemblyFileName == null) return; + + var destFile = Path.Combine(binFolder, assemblyFileName); + + if (_fileSystem.FileExists(destFile)) + { + _fileSystem.FileDelete(destFile); + } + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 9323a682..c8cf35cf 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -49,6 +49,16 @@ public ICommand CreateCommand(ScriptCsArgs args) return new CompositeCommand(installCommand, restoreCommand); } + if (args.Clean) + { + var cleanCommand = new CleanCommand( + args.ScriptName, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.PackageAssemblyResolver); + + return cleanCommand; + } + return new InvalidCommand(); } } diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index 1d11dfa0..171064b8 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -6,6 +6,8 @@ public interface IScriptCommand : ICommand { } public interface IRestoreCommand : ICommand { } + public interface ICleanCommand : ICommand { } + public interface IInstallCommand : ICommand { } public interface IInvalidCommand : ICommand { } diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index aa49af45..f88fc724 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -41,6 +41,7 @@ Properties\CommonVersionInfo.cs + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 77c0f061..7b65efac 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -18,6 +18,9 @@ public class ScriptCsArgs [ArgShortcut("restore")] public bool Restore { get; set; } + [ArgShortcut("clean")] + public bool Clean { get; set; } + [ArgShortcut("pre")] public bool AllowPreReleaseFlag { get; set; } From 6c2b7f4b2305555edef132b789b0ca8d4f32f350 Mon Sep 17 00:00:00 2001 From: Filip W Date: Wed, 27 Mar 2013 20:32:08 -0400 Subject: [PATCH 0156/1224] tests for #142 --- test/ScriptCs.Tests/CleanCommandTests.cs | 109 +++++++++++++++++++++ test/ScriptCs.Tests/CommandFactoryTests.cs | 12 +++ test/ScriptCs.Tests/RestoreCommandTests.cs | 3 - test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 + 4 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 test/ScriptCs.Tests/CleanCommandTests.cs diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs new file mode 100644 index 00000000..be2ce691 --- /dev/null +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -0,0 +1,109 @@ +using System; +using Moq; +using ScriptCs.Command; +using ScriptCs.Package; +using Xunit; + +namespace ScriptCs.Tests +{ + public class CleanCommandTests + { + public class ExecuteMethod + { + [Fact] + public void ShouldDeletePackagesFolder() + { + var args = new ScriptCsArgs { Clean = true }; + + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); + fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); + } + + [Fact] + public void ShouldDeleteBinFolder() + { + var args = new ScriptCsArgs { Clean = true }; + + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + } + + [Fact] + public void ShouldNotDeleteBinFolderIfDllsAreLeft() + { + var args = new ScriptCsArgs { Clean = true }; + + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); + fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); + } + + [Fact] + public void ShouldDeleteAllFilesResolvedFromPackages() + { + var args = new ScriptCsArgs { Clean = true }; + + var fs = new Mock(); + var resolver = new Mock(); + var executor = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); + + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); + resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + fs.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index f719e54c..9657e96b 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -89,6 +89,18 @@ public void ShouldRestoreWhenBothNameAndRestoreArePassed() (compositeCommand.Commands[1] is IScriptCommand).ShouldBeTrue(); } + [Fact] + public void ShouldCleanWhenCleanFlagIsPassed() + { + var args = new ScriptCsArgs { Clean = true, ScriptName = null }; + + var factory = new CommandFactory(CreateRoot()); + var result = factory.CreateCommand(args); + + result.ShouldNotBeNull(); + result.ShouldImplement(); + } + [Fact] public void ShouldReturnInvalidWhenNoNameOrInstallSet() { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index c2e8015e..1679a79e 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -1,11 +1,8 @@ using System; using System.IO; - using Moq; - using ScriptCs.Command; using ScriptCs.Package; - using Xunit; namespace ScriptCs.Tests diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 733cdd35..d7f85ffd 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -36,6 +36,7 @@ Properties\CommonVersionInfo.cs + From bc17cd04eb9a2fc2a98020d0e71eed0d1874466f Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 29 Mar 2013 18:56:02 -0400 Subject: [PATCH 0157/1224] issue #155, added default references & default namespaces --- src/ScriptCs.Core/IScriptEngine.cs | 12 ++++++------ src/ScriptCs.Core/ScriptExecutor.cs | 9 +++++---- src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index f8f8a8ad..698d33e7 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -2,9 +2,9 @@ namespace ScriptCs { - public interface IScriptEngine - { - string BaseDirectory { get; set; } - void Execute(string code, IEnumerable references, ScriptPackSession scriptPackSession); - } -} + public interface IScriptEngine + { + string BaseDirectory { get; set; } + void Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index cffda641..ab28988b 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -8,10 +8,11 @@ namespace ScriptCs { public class ScriptExecutor : IScriptExecutor { - private readonly IFileSystem _fileSystem; + private static readonly string[] DefaultReferences = new[] {"System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq"}; + private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks"}; + private readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; - private readonly IScriptEngine _scriptEngine; public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine) @@ -25,7 +26,7 @@ public void Execute(string script, IEnumerable paths, IEnumerable { "System", "System.Core" }.Union(paths); + var references = DefaultReferences.Union(paths); _scriptEngine.BaseDirectory = bin; @@ -35,7 +36,7 @@ public void Execute(string script, IEnumerable paths, IEnumerable references, ScriptPackSession scriptPackSession) + public void Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { var contexts = scriptPackSession.ScriptPacks.Select(x => x.GetContext()); var host = _scriptHostFactory.CreateScriptHost(contexts); @@ -33,7 +33,7 @@ public void Execute(string code, IEnumerable references, ScriptPackSessi foreach (var reference in references.Union(scriptPackSession.References).Distinct()) session.AddReference(reference); - foreach (var @namespace in scriptPackSession.Namespaces.Distinct()) + foreach (var @namespace in namespaces.Union(scriptPackSession.Namespaces).Distinct()) session.ImportNamespace(@namespace); Execute(code, session); From 467e2a4cd82323a1fc5e4beeda74478196485866 Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 29 Mar 2013 18:56:22 -0400 Subject: [PATCH 0158/1224] tests for #155 --- .../ScriptExecutorTests.cs | 51 +++++++++++++++++-- .../RoslynScriptDebuggerEngine.cs | 2 +- .../RoslynScriptEngineTests.cs | 2 +- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index def0bc7b..685ddcdd 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -119,7 +119,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut var recipes = Enumerable.Empty(); preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(code).Verifiable(); - scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny())); // act scriptExecutor.Execute(scriptName, paths, recipes); @@ -127,7 +127,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut // assert preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); - scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny()), Times.Once()); + scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); } @@ -135,6 +135,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut public void ShouldAddReferenceToEachDestinationFile() { // arrange + var defaultReferences = new[] {"System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq"}; var fileSystem = new Mock(); var scriptEngine = new Mock(); @@ -155,13 +156,13 @@ public void ShouldAddReferenceToEachDestinationFile() var destPaths = new string[] { "System", "System.Core", destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; - scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny())); + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); // act scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); // assert - scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(destPaths)), It.IsAny()), Times.Once()); + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); } [Fact] @@ -206,6 +207,48 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() scriptPack1.Verify(p => p.Terminate()); } + + [Fact] + public void ExecutorShouldPassDefaultNamespacesToEngine() + { + var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks"}; + + var fileSystem = new Mock(); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var engine = new Mock(); + + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine:engine); + + executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + + engine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); + } + + [Fact] + public void ExecutorShouldPassDefaultReferencesToEngine() + { + var defaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + + var fileSystem = new Mock(); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + + var engine = new Mock(); + + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); + + executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + + engine.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Except(defaultReferences).Any()), It.IsAny>(), It.IsAny()), Times.Exactly(1)); + } } } } \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs index c15b60b4..d3bed27f 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs @@ -36,7 +36,7 @@ public void ShouldThrowExceptionThrownByScriptWhenErrorOccurs() var exception = Assert.Throws( () => scriptEngine.Execute( - code, Enumerable.Empty(), new ScriptPackSession(Enumerable.Empty()))); + code, Enumerable.Empty(), Enumerable.Empty(), new ScriptPackSession(Enumerable.Empty()))); Console.WriteLine(exception.Message); diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 49bc5827..737f4b56 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -43,7 +43,7 @@ public void ShouldCreateScriptHostWithContexts() var scriptPackSession = new ScriptPackSession(new[] { scriptPack1.Object }); - engine.Execute(code, Enumerable.Empty(), scriptPackSession); + engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); } From 99546d79b4f437e8c26aa686f8b195f97e885edc Mon Sep 17 00:00:00 2001 From: Danielle Boldt Date: Fri, 29 Mar 2013 20:50:45 -0400 Subject: [PATCH 0159/1224] #132 adapted to the latest code Execute now returns a CommandResult --- src/ScriptCs/Command/VersionCommand.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index 4d9e57b6..83d9a145 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -4,10 +4,10 @@ namespace ScriptCs.Command { internal class VersionCommand : IVersionCommand { - public int Execute() + public CommandResult Execute() { Console.WriteLine(string.Format("ScriptCs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version)); - return 0; + return CommandResult.Success; } } } From 58c780c3ba6d92eba03d8b582b02ef48f3be392f Mon Sep 17 00:00:00 2001 From: Danielle Boldt Date: Fri, 29 Mar 2013 21:33:49 -0400 Subject: [PATCH 0160/1224] #132 Removing reference to ScriptExecuteCommand.cs File appears to be removed. Tried checking this in earlier and it apparently failed. --- src/ScriptCs/ScriptCs.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 1f5e7a26..934ff231 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -48,7 +48,6 @@ - From b971a96fdae637a60353956ee039b5325bbb9ebb Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 31 Mar 2013 00:17:51 -0300 Subject: [PATCH 0161/1224] # Updated to use Common.Logging in all projects, removing dependency to log4Net. --- src/ScriptCs.Core/DebugScriptExecutor.cs | 20 +++++++++---------- src/ScriptCs.Core/FilePreProcessor.cs | 6 ++---- src/ScriptCs.Core/ScriptCs.Core.csproj | 4 ++-- src/ScriptCs.Core/ScriptExecutor.cs | 3 +-- src/ScriptCs.Core/packages.config | 2 +- .../RoslynScriptDebuggerEngine.cs | 2 +- .../RoslynScriptEngine.cs | 2 +- .../ScriptCs.Engine.Roslyn.csproj | 4 ++-- src/ScriptCs.Engine.Roslyn/packages.config | 2 +- src/ScriptCs/Command/ExecuteScriptCommand.cs | 2 +- src/ScriptCs/CompositionRoot.cs | 7 +------ src/ScriptCs/LoggerConfigurator.cs | 20 ++++++++++++++++--- src/ScriptCs/Program.cs | 3 +-- src/ScriptCs/ScriptCs.csproj | 11 ++++++++-- src/ScriptCs/ScriptServiceRoot.cs | 2 +- src/ScriptCs/app.config | 15 ++++++++++++-- src/ScriptCs/packages.config | 4 +++- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 2 +- .../ScriptCs.Core.Tests.csproj | 4 ++-- .../ScriptExecutorTests.cs | 2 +- test/ScriptCs.Core.Tests/packages.config | 2 +- .../RoslynScriptDebuggerEngine.cs | 2 +- .../RoslynScriptEngineTests.cs | 2 +- .../ScriptCs.Engine.Roslyn.Tests.csproj | 4 ++-- .../packages.config | 2 +- test/ScriptCs.Tests/CleanCommandTests.cs | 3 +-- test/ScriptCs.Tests/CommandFactoryTests.cs | 2 +- .../ExecuteScriptCommandTests.cs | 2 +- test/ScriptCs.Tests/InstallCommandTests.cs | 2 +- test/ScriptCs.Tests/RestoreCommandTests.cs | 3 +-- test/ScriptCs.Tests/ScriptCs.Tests.csproj | 4 ++-- test/ScriptCs.Tests/VersionCommandTests.cs | 6 ++---- test/ScriptCs.Tests/packages.config | 2 +- 33 files changed, 87 insertions(+), 66 deletions(-) diff --git a/src/ScriptCs.Core/DebugScriptExecutor.cs b/src/ScriptCs.Core/DebugScriptExecutor.cs index 6dd04327..5d69d0a4 100644 --- a/src/ScriptCs.Core/DebugScriptExecutor.cs +++ b/src/ScriptCs.Core/DebugScriptExecutor.cs @@ -1,12 +1,12 @@ -namespace ScriptCs -{ - using log4net; +using Common.Logging; - public class DebugScriptExecutor : ScriptExecutor - { - public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) - : base(fileSystem, filePreProcessor, scriptEngine, logger) - { - } - } +namespace ScriptCs +{ + public class DebugScriptExecutor : ScriptExecutor + { + public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) + : base(fileSystem, filePreProcessor, scriptEngine, logger) + { + } + } } diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index db73b453..b1479b59 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -1,11 +1,9 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; +using Common.Logging; namespace ScriptCs { - using log4net; - public class FilePreProcessor : IFilePreProcessor { private const string LoadString = "#load "; diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index f3069d27..0e296c56 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -18,8 +18,8 @@ ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll - - ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll False diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 1d2fee4b..153bde87 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; - -using log4net; +using Common.Logging; using ScriptCs.Contracts; namespace ScriptCs diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index cd130584..c646312a 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -2,6 +2,6 @@ - + \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index a8cf37b9..41cdec4c 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -2,7 +2,7 @@ using System.IO; using System.Linq; using System.Reflection; -using log4net; +using Common.Logging; using Roslyn.Scripting; using ScriptCs.Exceptions; diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index a0c80589..0cfb838a 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using log4net; +using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 74a70d5f..9523ab73 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -9,8 +9,8 @@ ..\..\ - - ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll diff --git a/src/ScriptCs.Engine.Roslyn/packages.config b/src/ScriptCs.Engine.Roslyn/packages.config index bf177711..21dfd7fa 100644 --- a/src/ScriptCs.Engine.Roslyn/packages.config +++ b/src/ScriptCs.Engine.Roslyn/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 8d9343b3..1cd2cd02 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using log4net; +using Common.Logging; namespace ScriptCs.Command { diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 4dbe6a45..db43d243 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -2,16 +2,11 @@ using System.ComponentModel.Composition.Hosting; using Autofac; using Autofac.Integration.Mef; +using Common.Logging; using ScriptCs.Engine.Roslyn; using ScriptCs.Package; using ScriptCs.Package.InstallationProvider; -using log4net; -using log4net.Appender; -using log4net.Core; -using log4net.Layout; -using log4net.Repository.Hierarchy; - namespace ScriptCs { public class CompositionRoot diff --git a/src/ScriptCs/LoggerConfigurator.cs b/src/ScriptCs/LoggerConfigurator.cs index 547f3a0a..403e2db0 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/src/ScriptCs/LoggerConfigurator.cs @@ -4,6 +4,10 @@ using log4net.Layout; using log4net.Repository.Hierarchy; +using ICommonLog = Common.Logging.ILog; + +using Common.Logging.Log4Net; + namespace ScriptCs { public class LoggerConfigurator @@ -13,7 +17,7 @@ public class LoggerConfigurator private readonly string _logLevel; - private ILog _logger; + private ICommonLog _logger; public LoggerConfigurator(string logLevel) { @@ -23,7 +27,7 @@ public LoggerConfigurator(string logLevel) public void Configure() { var hierarchy = (Hierarchy)LogManager.GetRepository(); - _logger = LogManager.GetLogger(LoggerName); + var logger = LogManager.GetLogger(LoggerName); var consoleAppender = new ConsoleAppender { Layout = new PatternLayout(Pattern), @@ -33,11 +37,21 @@ public void Configure() hierarchy.Root.AddAppender(consoleAppender); hierarchy.Root.Level = Level.All; hierarchy.Configured = true; + + _logger = new CodeConfigurableLog4NetLogger(logger); } - public ILog GetLogger() + public ICommonLog GetLogger() { return _logger; } + + private class CodeConfigurableLog4NetLogger : Log4NetLogger + { + protected internal CodeConfigurableLog4NetLogger(ILoggerWrapper log) + : base(log) + { + } + } } } \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 24da3a65..0e027a12 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,7 +1,6 @@ -using log4net; +using Common.Logging; using PowerArgs; using ScriptCs.Command; -using System; namespace ScriptCs { diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 9061ace8..e8d20256 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -21,8 +21,15 @@ ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll - - ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll + + + ..\..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll + + + False + ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll ..\..\packages\PowerArgs.1.2.0.1\lib\net40\PowerArgs.dll diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index f2538c95..c11f3afd 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -1,4 +1,4 @@ -using log4net; +using Common.Logging; using ScriptCs.Package; namespace ScriptCs diff --git a/src/ScriptCs/app.config b/src/ScriptCs/app.config index c5e1daef..cb1b9770 100644 --- a/src/ScriptCs/app.config +++ b/src/ScriptCs/app.config @@ -1,3 +1,14 @@ - + - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index 467279a8..8185c9b9 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -1,6 +1,8 @@  - + + + \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index d2914dfc..aad6ca55 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using log4net; +using Common.Logging; using Moq; using Should; using Xunit; diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 6e109f87..ebc50c32 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -9,8 +9,8 @@ ..\..\ - - ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 04ebd171..e303c23d 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using log4net; +using Common.Logging; using Moq; using ScriptCs.Contracts; using Should; diff --git a/test/ScriptCs.Core.Tests/packages.config b/test/ScriptCs.Core.Tests/packages.config index 42f2ff5a..ae265215 100644 --- a/test/ScriptCs.Core.Tests/packages.config +++ b/test/ScriptCs.Core.Tests/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs index 818450cf..9c06e4ed 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs @@ -1,6 +1,6 @@ using System; using System.Linq; -using log4net; +using Common.Logging; using Moq; using ScriptCs.Contracts; using ScriptCs.Engine.Roslyn; diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 9c5a794d..b0382ead 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; +using Common.Logging; using Moq; using ScriptCs.Contracts; using ScriptCs.Engine.Roslyn; using Xunit; -using log4net; namespace ScriptCs.Tests { diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj index f98204b8..87f4c069 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj @@ -9,8 +9,8 @@ ..\..\ - - ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll diff --git a/test/ScriptCs.Engine.Roslyn.Tests/packages.config b/test/ScriptCs.Engine.Roslyn.Tests/packages.config index 50922081..54df82f8 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/packages.config +++ b/test/ScriptCs.Engine.Roslyn.Tests/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index bc59d9c5..4b627501 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,4 +1,5 @@ using System; +using Common.Logging; using Moq; using ScriptCs.Command; using ScriptCs.Package; @@ -6,8 +7,6 @@ namespace ScriptCs.Tests { - using log4net; - public class CleanCommandTests { public class ExecuteMethod diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index d7eaa66e..fa37a561 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -1,4 +1,4 @@ -using log4net; +using Common.Logging; using Moq; using ScriptCs.Command; using ScriptCs.Package; diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 80574233..58feec14 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.IO; -using log4net; +using Common.Logging; using Moq; using ScriptCs.Command; using ScriptCs.Contracts; diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 9e167efc..4d57cf36 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.Versioning; -using log4net; +using Common.Logging; using Moq; using ScriptCs.Command; using ScriptCs.Package; diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index d764af89..eb9d4388 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Common.Logging; using Moq; using ScriptCs.Command; using ScriptCs.Package; @@ -7,8 +8,6 @@ namespace ScriptCs.Tests { - using log4net; - public class RestoreCommandTests { public class TheExecuteMethod diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 8addad92..bfd05350 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -9,9 +9,9 @@ ..\..\ - + False - ..\..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index ced4e6b9..2391c7e9 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -1,4 +1,5 @@ -using Moq; +using Common.Logging; +using Moq; using ScriptCs.Command; using ScriptCs.Package; using System.IO; @@ -6,13 +7,10 @@ namespace ScriptCs.Tests { - using log4net; - public class VersionCommandTests { public class ExecuteMethod { - private readonly System.Version _currentVersion; System.Text.StringBuilder _outputText; diff --git a/test/ScriptCs.Tests/packages.config b/test/ScriptCs.Tests/packages.config index eb044e0d..667f949f 100644 --- a/test/ScriptCs.Tests/packages.config +++ b/test/ScriptCs.Tests/packages.config @@ -1,6 +1,6 @@  - + From 2978f9e98f321339388fbdb484370e209aa1dc6f Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 31 Mar 2013 00:37:50 -0300 Subject: [PATCH 0162/1224] # Updated commands to take advantage of logger instead of using Console.WriteLine --- src/ScriptCs/Command/CleanCommand.cs | 13 +++++++++---- src/ScriptCs/Command/CommandFactory.cs | 14 +++++++++----- src/ScriptCs/Command/ExecuteScriptCommand.cs | 2 +- src/ScriptCs/Command/InstallCommand.cs | 16 +++++++++++----- src/ScriptCs/Command/InvalidCommand.cs | 13 ++++++++++--- src/ScriptCs/Command/RestoreCommand.cs | 16 ++++++++++------ src/ScriptCs/Command/VersionCommand.cs | 2 +- 7 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/ScriptCs/Command/CleanCommand.cs b/src/ScriptCs/Command/CleanCommand.cs index 7ed5d884..5941dc2c 100644 --- a/src/ScriptCs/Command/CleanCommand.cs +++ b/src/ScriptCs/Command/CleanCommand.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using Common.Logging; namespace ScriptCs.Command { @@ -9,17 +10,21 @@ internal class CleanCommand : ICleanCommand private readonly string _scriptName; private readonly IFileSystem _fileSystem; private readonly IPackageAssemblyResolver _packageAssemblyResolver; + private readonly ILog _logger; - public CleanCommand(string scriptName, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver) + public CleanCommand(string scriptName, + IFileSystem fileSystem, + IPackageAssemblyResolver packageAssemblyResolver, ILog logger) { _scriptName = scriptName; _fileSystem = fileSystem; _packageAssemblyResolver = packageAssemblyResolver; + _logger = logger; } public CommandResult Execute() { - Console.WriteLine("Cleaning initiated..."); + _logger.Info("Cleaning initiated..."); var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); var binFolder = Path.Combine(workingDirectory, Constants.BinFolder); @@ -46,12 +51,12 @@ public CommandResult Execute() if (_fileSystem.DirectoryExists(packageFolder)) _fileSystem.DeleteDirectory(packageFolder); - Console.WriteLine("Clean completed successfully."); + _logger.Info("Clean completed successfully."); return CommandResult.Success; } catch (Exception e) { - Console.WriteLine("Clean failed: {0}.", e.Message); + _logger.ErrorFormat("Clean failed: {0}.", e.Message); return CommandResult.Error; } } diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 03740808..9ffaa21e 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -25,7 +25,8 @@ public ICommand CreateCommand(ScriptCsArgs args) var restoreCommand = new RestoreCommand( args.ScriptName, _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver); + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.Logger); return new CompositeCommand(restoreCommand, executeCommand); } @@ -40,12 +41,14 @@ public ICommand CreateCommand(ScriptCsArgs args) args.AllowPreReleaseFlag, _scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.PackageInstaller); + _scriptServiceRoot.PackageInstaller, + _scriptServiceRoot.Logger); var restoreCommand = new RestoreCommand( args.Install, _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver); + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.Logger); return new CompositeCommand(installCommand, restoreCommand); } @@ -55,7 +58,8 @@ public ICommand CreateCommand(ScriptCsArgs args) var cleanCommand = new CleanCommand( args.ScriptName, _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver); + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.Logger); return cleanCommand; } @@ -65,7 +69,7 @@ public ICommand CreateCommand(ScriptCsArgs args) return new VersionCommand(); } - return new InvalidCommand(); + return new InvalidCommand(_scriptServiceRoot.Logger); } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 1cd2cd02..11adc661 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -25,7 +25,7 @@ public ExecuteScriptCommand(string script, _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; - this._logger = logger; + _logger = logger; } public CommandResult Execute() diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index d88ca79d..9771c4de 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -6,6 +6,8 @@ namespace ScriptCs.Command { + using Common.Logging; + internal class InstallCommand : IInstallCommand { private readonly string _name; @@ -18,37 +20,41 @@ internal class InstallCommand : IInstallCommand private readonly IPackageInstaller _packageInstaller; + private readonly ILog _logger; + public InstallCommand( string name, bool allowPre, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, - IPackageInstaller packageInstaller) + IPackageInstaller packageInstaller, + ILog logger) { _name = name; _allowPre = allowPre; _fileSystem = fileSystem; _packageAssemblyResolver = packageAssemblyResolver; _packageInstaller = packageInstaller; + _logger = logger; } public CommandResult Execute() { - Console.WriteLine("Installing packages..."); + _logger.Info("Installing packages..."); var workingDirectory = _fileSystem.CurrentDirectory; var packages = GetPackages(workingDirectory); try { - _packageInstaller.InstallPackages(packages, _allowPre, Console.WriteLine); + _packageInstaller.InstallPackages(packages, _allowPre, _logger.Info); - Console.WriteLine("Installation completed successfully."); + _logger.Info("Installation completed successfully."); return CommandResult.Success; } catch (Exception e) { - Console.WriteLine("Installation failed: {0}.", e.Message); + _logger.ErrorFormat("Installation failed: {0}.", e.Message); return CommandResult.Error; } } diff --git a/src/ScriptCs/Command/InvalidCommand.cs b/src/ScriptCs/Command/InvalidCommand.cs index 228deace..a1437bc3 100644 --- a/src/ScriptCs/Command/InvalidCommand.cs +++ b/src/ScriptCs/Command/InvalidCommand.cs @@ -1,13 +1,20 @@ -using System; -using PowerArgs; +using PowerArgs; +using Common.Logging; namespace ScriptCs.Command { internal class InvalidCommand : IInvalidCommand { + private readonly ILog _logger; + + public InvalidCommand(ILog logger) + { + _logger = logger; + } + public CommandResult Execute() { - Console.WriteLine(ArgUsage.GetUsage()); + _logger.Fatal(ArgUsage.GetUsage()); return CommandResult.Error; } } diff --git a/src/ScriptCs/Command/RestoreCommand.cs b/src/ScriptCs/Command/RestoreCommand.cs index ea5bd7b2..6f6b155b 100644 --- a/src/ScriptCs/Command/RestoreCommand.cs +++ b/src/ScriptCs/Command/RestoreCommand.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Common.Logging; namespace ScriptCs.Command { @@ -9,16 +10,19 @@ internal class RestoreCommand : IRestoreCommand private readonly IFileSystem _fileSystem; private readonly IPackageAssemblyResolver _packageAssemblyResolver; - public RestoreCommand(string scriptName, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver) + private readonly ILog _logger; + + public RestoreCommand(string scriptName, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, ILog logger) { _scriptName = scriptName; _fileSystem = fileSystem; _packageAssemblyResolver = packageAssemblyResolver; + _logger = logger; } public CommandResult Execute() { - Console.WriteLine("Copying assemblies to bin folder..."); + _logger.Info("Copying assemblies to bin folder..."); var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); var binFolder = Path.Combine(workingDirectory, Constants.BinFolder); @@ -34,12 +38,12 @@ public CommandResult Execute() CopyFile(package, binFolder); } - Console.WriteLine("Restore completed successfully."); + _logger.Info("Restore completed successfully."); return CommandResult.Success; } catch (Exception e) { - Console.WriteLine("Restore failed: {0}.", e.Message); + _logger.ErrorFormat("Restore failed: {0}.", e.Message); return CommandResult.Error; } } @@ -56,13 +60,13 @@ private void CopyFile(string package, string binFolder) if (sourceFileLastWriteTime == destFileLastWriteTime) { - Console.WriteLine("Skipped: {0}.", assemblyFileName); + _logger.InfoFormat("Skipped: {0}.", assemblyFileName); return; } _fileSystem.Copy(package, destFile, true); - Console.WriteLine("Copied: {0}.", assemblyFileName); + _logger.InfoFormat("Copied: {0}.", assemblyFileName); } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index 83d9a145..4bce8bee 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -6,7 +6,7 @@ internal class VersionCommand : IVersionCommand { public CommandResult Execute() { - Console.WriteLine(string.Format("ScriptCs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version)); + Console.WriteLine("ScriptCs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); return CommandResult.Success; } } From 61b366d686081e834a47816f67b6684208b8b0e9 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 31 Mar 2013 17:14:55 -0300 Subject: [PATCH 0163/1224] # Minor updates based on feedback --- src/ScriptCs.Core/ScriptExecutor.cs | 27 -------------- src/ScriptCs/Command/InstallCommand.cs | 4 +-- src/ScriptCs/Properties/chocolateyInstall.ps1 | 35 ++++++++++++------- src/ScriptCs/Properties/chocolateyinstall.ps1 | 35 ++++++++++++------- 4 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 153bde87..985b8d83 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -43,32 +43,5 @@ public void Execute(string script, IEnumerable paths, IEnumerable PrepareBinFolder(IEnumerable paths, string bin) - { - var files = new List(); - - if (!_fileSystem.DirectoryExists(bin)) - { - _logger.DebugFormat("Creating directory {0}", bin); - _fileSystem.CreateDirectory(bin); - } - - foreach (var file in paths) - { - var destFile = Path.Combine(bin, Path.GetFileName(file)); - var sourceFileLastWriteTime = _fileSystem.GetLastWriteTime(file); - var destFileLastWriteTime = _fileSystem.GetLastWriteTime(destFile); - if (sourceFileLastWriteTime != destFileLastWriteTime) - { - _logger.DebugFormat("Copying file {0} to bin folder {1}", file, destFile); - _fileSystem.Copy(file, destFile, true); - } - - files.Add(destFile); - } - - return files; - } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index 9771c4de..319d79bf 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; using System.Runtime.Versioning; - +using Common.Logging; using ScriptCs.Package; namespace ScriptCs.Command { - using Common.Logging; - internal class InstallCommand : IInstallCommand { private readonly string _name; diff --git a/src/ScriptCs/Properties/chocolateyInstall.ps1 b/src/ScriptCs/Properties/chocolateyInstall.ps1 index 923c480d..5ab98ff0 100644 --- a/src/ScriptCs/Properties/chocolateyInstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyInstall.ps1 @@ -1,19 +1,28 @@ try { $tools = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" - $nugetExe = "$env:ChocolateyInstall\ChocolateyInstall\nuget" - $binPath="$env:appdata\scriptcs" + $nuget = "$env:ChocolateyInstall\ChocolateyInstall\nuget" + $binPath = "$env:APPDATA\scriptcs" + $nugetPath = "$tools\nugets" - if(!(Test-Path $binpath)){mkdir $binPath} - Copy-Item "$tools\scriptcs\*" $binPath -force - mkdir "$tools\nugets" - "nuget.core","Roslyn.Compilers.Common","Roslyn.Compilers.CSharp","PowerArgs" | - % {.$nugetexe install $_ -o "$tools\nugets"} - Get-childItem "$tools\nugets" -filter *.dll -recurse | % {Copy-Item $_.FullName $binPath } - New-Item "$tools\scriptcs\scriptcs.exe.ignore" -type file -force - Remove-Item $tools\..\lib -recurse -force - Install-ChocolateyPath $binPath - write-host "scriptcs.exe locted in $binpath is now in your path. " -foregroundcolor darkyellow - write-host "You may need to open a new console for the new path to take effect. Happy scripting!" -foregroundcolor darkyellow + New-Item $binPath -ItemType Directory -Force | Out-Null + + Copy-Item "$tools\scriptcs\*" $binPath -Force + + Write-Host "Retrieving NuGet dependencies..." -ForegroundColor DarkYellow + + "NuGet.Core","Autofac.Mef","Roslyn.Compilers.CSharp","PowerArgs" | %{ .$nuget install $_ -o $nugetPath -nocache } | Out-Null + + Get-ChildItem $nugetPath -Filter "*.dll" -Recurse | %{ Copy-Item $_.FullName $binPath -Force } + Remove-Item $nugetPath -Recurse -Force + New-Item "$tools\scriptcs\scriptcs.exe.ignore" -ItemType File -Force | Out-Null + + if (Test-Path "$tools\..\lib") { + Remove-Item "$tools\..\lib" -Recurse -Force + } + + Install-ChocolateyPath $binPath + Write-Host "scriptcs.exe has been installed to $binpath and has been added to your path." -ForegroundColor DarkYellow + Write-Host "You may need to open a new console for the new path to take effect. Happy scripting!" -ForegroundColor DarkYellow Write-ChocolateySuccess 'scriptcs' } catch { Write-ChocolateyFailure 'scriptcs' "$($_.Exception.Message)" diff --git a/src/ScriptCs/Properties/chocolateyinstall.ps1 b/src/ScriptCs/Properties/chocolateyinstall.ps1 index 923c480d..5ab98ff0 100644 --- a/src/ScriptCs/Properties/chocolateyinstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyinstall.ps1 @@ -1,19 +1,28 @@ try { $tools = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" - $nugetExe = "$env:ChocolateyInstall\ChocolateyInstall\nuget" - $binPath="$env:appdata\scriptcs" + $nuget = "$env:ChocolateyInstall\ChocolateyInstall\nuget" + $binPath = "$env:APPDATA\scriptcs" + $nugetPath = "$tools\nugets" - if(!(Test-Path $binpath)){mkdir $binPath} - Copy-Item "$tools\scriptcs\*" $binPath -force - mkdir "$tools\nugets" - "nuget.core","Roslyn.Compilers.Common","Roslyn.Compilers.CSharp","PowerArgs" | - % {.$nugetexe install $_ -o "$tools\nugets"} - Get-childItem "$tools\nugets" -filter *.dll -recurse | % {Copy-Item $_.FullName $binPath } - New-Item "$tools\scriptcs\scriptcs.exe.ignore" -type file -force - Remove-Item $tools\..\lib -recurse -force - Install-ChocolateyPath $binPath - write-host "scriptcs.exe locted in $binpath is now in your path. " -foregroundcolor darkyellow - write-host "You may need to open a new console for the new path to take effect. Happy scripting!" -foregroundcolor darkyellow + New-Item $binPath -ItemType Directory -Force | Out-Null + + Copy-Item "$tools\scriptcs\*" $binPath -Force + + Write-Host "Retrieving NuGet dependencies..." -ForegroundColor DarkYellow + + "NuGet.Core","Autofac.Mef","Roslyn.Compilers.CSharp","PowerArgs" | %{ .$nuget install $_ -o $nugetPath -nocache } | Out-Null + + Get-ChildItem $nugetPath -Filter "*.dll" -Recurse | %{ Copy-Item $_.FullName $binPath -Force } + Remove-Item $nugetPath -Recurse -Force + New-Item "$tools\scriptcs\scriptcs.exe.ignore" -ItemType File -Force | Out-Null + + if (Test-Path "$tools\..\lib") { + Remove-Item "$tools\..\lib" -Recurse -Force + } + + Install-ChocolateyPath $binPath + Write-Host "scriptcs.exe has been installed to $binpath and has been added to your path." -ForegroundColor DarkYellow + Write-Host "You may need to open a new console for the new path to take effect. Happy scripting!" -ForegroundColor DarkYellow Write-ChocolateySuccess 'scriptcs' } catch { Write-ChocolateyFailure 'scriptcs' "$($_.Exception.Message)" From 1fc7518a926524664cf9a5eb66dcba6426eaea24 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 31 Mar 2013 17:19:28 -0300 Subject: [PATCH 0164/1224] Deleted chocolateyinstall.ps1 (install instead of Install) --- src/ScriptCs/Properties/chocolateyinstall.ps1 | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 src/ScriptCs/Properties/chocolateyinstall.ps1 diff --git a/src/ScriptCs/Properties/chocolateyinstall.ps1 b/src/ScriptCs/Properties/chocolateyinstall.ps1 deleted file mode 100644 index 5ab98ff0..00000000 --- a/src/ScriptCs/Properties/chocolateyinstall.ps1 +++ /dev/null @@ -1,30 +0,0 @@ -try { - $tools = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" - $nuget = "$env:ChocolateyInstall\ChocolateyInstall\nuget" - $binPath = "$env:APPDATA\scriptcs" - $nugetPath = "$tools\nugets" - - New-Item $binPath -ItemType Directory -Force | Out-Null - - Copy-Item "$tools\scriptcs\*" $binPath -Force - - Write-Host "Retrieving NuGet dependencies..." -ForegroundColor DarkYellow - - "NuGet.Core","Autofac.Mef","Roslyn.Compilers.CSharp","PowerArgs" | %{ .$nuget install $_ -o $nugetPath -nocache } | Out-Null - - Get-ChildItem $nugetPath -Filter "*.dll" -Recurse | %{ Copy-Item $_.FullName $binPath -Force } - Remove-Item $nugetPath -Recurse -Force - New-Item "$tools\scriptcs\scriptcs.exe.ignore" -ItemType File -Force | Out-Null - - if (Test-Path "$tools\..\lib") { - Remove-Item "$tools\..\lib" -Recurse -Force - } - - Install-ChocolateyPath $binPath - Write-Host "scriptcs.exe has been installed to $binpath and has been added to your path." -ForegroundColor DarkYellow - Write-Host "You may need to open a new console for the new path to take effect. Happy scripting!" -ForegroundColor DarkYellow - Write-ChocolateySuccess 'scriptcs' -} catch { - Write-ChocolateyFailure 'scriptcs' "$($_.Exception.Message)" - throw -} \ No newline at end of file From a06653e913048f2c5f7bf728f9c6fdf95d943256 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 31 Mar 2013 17:30:26 -0300 Subject: [PATCH 0165/1224] # Updated VersionCommand.cs with name scriptcs instead of ScriptCs --- src/ScriptCs/Command/VersionCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index 4bce8bee..d51b4a0a 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -6,7 +6,7 @@ internal class VersionCommand : IVersionCommand { public CommandResult Execute() { - Console.WriteLine("ScriptCs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + Console.WriteLine("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); return CommandResult.Success; } } From b5e17ed40bc9958a9cb8dd4fcdd364cd727efae7 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 31 Mar 2013 17:33:36 -0300 Subject: [PATCH 0166/1224] # Updated VersionCommandTests.cs to assert for scriptcs instead of ScriptCs --- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 2391c7e9..f321d96a 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -50,7 +50,7 @@ public void VersionCommandShouldOutputVersion() result.Execute(); - Assert.Contains("ScriptCs version " + _currentVersion.ToString(), _outputText.ToString()); + Assert.Contains("scriptcs version " + _currentVersion.ToString(), _outputText.ToString()); } } } From 45123a8aa41ffa96faf15ee317b2f7f6a4544f9a Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 1 Apr 2013 01:23:12 -0700 Subject: [PATCH 0167/1224] Added Get method to ScriptHost and tests. Introduced IScriptHostFactory and introduced it in several places in code and tests --- src/ScriptCs.Core/IScriptPackManager.cs | 9 +++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs.Core/ScriptPackManager.cs | 2 +- .../IScriptHostFactory.cs | 2 +- .../RoslynScriptEngine.cs | 2 +- src/ScriptCs.Engine.Roslyn/ScriptHost.cs | 12 +++++-- .../ScriptHostFactory.cs | 4 +-- .../RoslynScriptEngineTests.cs | 4 +-- .../ScriptCs.Engine.Roslyn.Tests.csproj | 1 + .../ScriptHostTests.cs | 36 +++++++++++++++++++ 10 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 src/ScriptCs.Core/IScriptPackManager.cs create mode 100644 test/ScriptCs.Engine.Roslyn.Tests/ScriptHostTests.cs diff --git a/src/ScriptCs.Core/IScriptPackManager.cs b/src/ScriptCs.Core/IScriptPackManager.cs new file mode 100644 index 00000000..dc69fff7 --- /dev/null +++ b/src/ScriptCs.Core/IScriptPackManager.cs @@ -0,0 +1,9 @@ +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public interface IScriptPackManager + { + TContext Get() where TContext : IScriptPackContext; + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 123eb7fe..891f53a0 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -47,6 +47,7 @@ + diff --git a/src/ScriptCs.Core/ScriptPackManager.cs b/src/ScriptCs.Core/ScriptPackManager.cs index 4d03d723..6f4c6ad9 100644 --- a/src/ScriptCs.Core/ScriptPackManager.cs +++ b/src/ScriptCs.Core/ScriptPackManager.cs @@ -4,7 +4,7 @@ namespace ScriptCs { - public class ScriptPackManager + public class ScriptPackManager : IScriptPackManager { private IDictionary _contexts = new Dictionary(); diff --git a/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs b/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs index f344dd95..5c7a71b2 100644 --- a/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs +++ b/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs @@ -6,6 +6,6 @@ namespace ScriptCs.Engine.Roslyn { public interface IScriptHostFactory { - ScriptHost CreateScriptHost(IEnumerable contexts); + ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager); } } diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ea336476..dc4c92d6 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -26,7 +26,7 @@ public string BaseDirectory public void Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { var contexts = scriptPackSession.ScriptPacks.Select(x => x.GetContext()); - var host = _scriptHostFactory.CreateScriptHost(contexts); + var host = _scriptHostFactory.CreateScriptHost(new ScriptPackManager(contexts)); var session = _scriptEngine.CreateSession(host); diff --git a/src/ScriptCs.Engine.Roslyn/ScriptHost.cs b/src/ScriptCs.Engine.Roslyn/ScriptHost.cs index a70b7c92..cc54563a 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptHost.cs +++ b/src/ScriptCs.Engine.Roslyn/ScriptHost.cs @@ -6,11 +6,17 @@ namespace ScriptCs.Engine.Roslyn { public class ScriptHost { - public ScriptHost(IEnumerable contexts) + private IScriptPackManager _scriptPackManager; + + public ScriptHost(IScriptPackManager scriptPackManager) + { + _scriptPackManager = scriptPackManager; + } + + public T Get() where T:IScriptPackContext { - ScriptPackManager = new ScriptPackManager(contexts); + return _scriptPackManager.Get(); } - public ScriptPackManager ScriptPackManager { get; private set; } } } diff --git a/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs b/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs index 93b9d7c9..0d8c84bd 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs +++ b/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs @@ -5,9 +5,9 @@ namespace ScriptCs.Engine.Roslyn { public class ScriptHostFactory : IScriptHostFactory { - public ScriptHost CreateScriptHost(IEnumerable contexts) + public ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager) { - return new ScriptHost(contexts); + return new ScriptHost(scriptPackManager); } } } \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 737f4b56..75e6ff89 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -31,7 +31,7 @@ public void ShouldCreateScriptHostWithContexts() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny>())).Returns((IEnumerable c) => new ScriptHost(c)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); var code = "var a = 0;"; @@ -45,7 +45,7 @@ public void ShouldCreateScriptHostWithContexts() engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); - scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny>())); + scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny())); } } diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj index 4f9bc964..433257b4 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj @@ -42,6 +42,7 @@ + diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptHostTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/ScriptHostTests.cs new file mode 100644 index 00000000..97f2ab8c --- /dev/null +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptHostTests.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Contracts; +using ScriptCs.Engine.Roslyn; +using Xunit; +using Should; +using Moq; + +namespace ScriptCs.Tests +{ + public class ScriptHostTests + { + public class TheGetMethod + { + private Mock _mockContext = new Mock(); + private Mock _mockScriptPackManager = new Mock(); + private ScriptHost _scriptHost; + + public TheGetMethod() + { + _scriptHost = new ScriptHost(_mockScriptPackManager.Object); + _mockScriptPackManager.Setup(s => s.Get()).Returns(_mockContext.Object); + } + + [Fact] + public void ShoulGetScriptPackFromScriptPackManagerWhenInvoked() + { + var result = _scriptHost.Get(); + _mockScriptPackManager.Verify(s=>s.Get()); + } + } + } +} From 5b8af2226535e6f2f7192f618b860afb34f4fa56 Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Mon, 1 Apr 2013 16:02:17 +0300 Subject: [PATCH 0168/1224] Fixes #164. PowerArg package updated. --- src/ScriptCs/ScriptCs.csproj | 5 +++-- src/ScriptCs/packages.config | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 934ff231..f8be15cf 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -21,8 +21,9 @@ ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll - - ..\..\packages\PowerArgs.1.2.0.1\lib\net40\PowerArgs.dll + + False + ..\..\packages\PowerArgs.1.4.0.0\lib\net40\PowerArgs.dll diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index a22262dc..b185dba1 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file From fc93e538ee734873cdf9a5a128b5752b42bd40fd Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Mon, 1 Apr 2013 16:51:33 +0300 Subject: [PATCH 0169/1224] #161 Passing an invalid command-line argument will show arguments help. --- src/ScriptCs/Program.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 7d53a2f3..b2e24b07 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -6,9 +6,20 @@ namespace ScriptCs { internal class Program { - private static int Main(string[] args) + private static int Main(string[] args) { - var commandArgs = Args.Parse(args); + ScriptCsArgs commandArgs; + + try + { + commandArgs = Args.Parse(args); + } + catch (ArgException ex) + { + commandArgs = new ScriptCsArgs(); + + Console.WriteLine(ex.Message); + } var debug = commandArgs.DebugFlag; var compositionRoot = new CompositionRoot(debug); From 6376352d44f3e42b7cfb15ee4fe08728596ef085 Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Mon, 1 Apr 2013 16:54:52 +0300 Subject: [PATCH 0170/1224] Fancy command-line arguments help. --- src/ScriptCs/Command/InvalidCommand.cs | 2 +- src/ScriptCs/ScriptCsArgs.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/InvalidCommand.cs b/src/ScriptCs/Command/InvalidCommand.cs index 228deace..e9a0c50b 100644 --- a/src/ScriptCs/Command/InvalidCommand.cs +++ b/src/ScriptCs/Command/InvalidCommand.cs @@ -7,7 +7,7 @@ internal class InvalidCommand : IInvalidCommand { public CommandResult Execute() { - Console.WriteLine(ArgUsage.GetUsage()); + ArgUsage.GetStyledUsage().Write(); return CommandResult.Error; } } diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 33497362..86a68aae 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -2,6 +2,7 @@ namespace ScriptCs { + [ArgExample("scriptcs server.csx -debug", "Shows how to start the script with debug mode switched on")] public class ScriptCsArgs { [ArgDescription("Script file name")] From 1984a1e439d6a8f8af2e45de313356a4d65c3569 Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Mon, 1 Apr 2013 20:19:40 +0300 Subject: [PATCH 0171/1224] Fixes #161 Error message added (with PowerArgs exception message parsing). --- src/ScriptCs/Program.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index b2e24b07..ee76d718 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -10,7 +10,8 @@ private static int Main(string[] args) { ScriptCsArgs commandArgs; - try + const string unexpectedArgumentMessage = "Unexpected Argument: "; + try { commandArgs = Args.Parse(args); } @@ -18,7 +19,15 @@ private static int Main(string[] args) { commandArgs = new ScriptCsArgs(); - Console.WriteLine(ex.Message); + if (ex.Message.StartsWith(unexpectedArgumentMessage)) + { + var token = ex.Message.Substring(unexpectedArgumentMessage.Length); + Console.WriteLine("Parameter \"{0}\" is not supported!", token); + } + else + { + Console.WriteLine(ex.Message); + } } var debug = commandArgs.DebugFlag; From 046ff98084fb6b4a3c5fccbeeaf251c7af9b4012 Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Thu, 4 Apr 2013 13:36:50 +0300 Subject: [PATCH 0172/1224] Fixes #165. Command-line arguments descriptions added. --- src/ScriptCs/ScriptCsArgs.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 86a68aae..60eff811 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -5,7 +5,7 @@ namespace ScriptCs [ArgExample("scriptcs server.csx -debug", "Shows how to start the script with debug mode switched on")] public class ScriptCsArgs { - [ArgDescription("Script file name")] + [ArgDescription("Script file name, must be specified first")] [ArgPosition(0)] public string ScriptName { get; set; } @@ -13,15 +13,19 @@ public class ScriptCsArgs [ArgShortcut("debug")] public bool DebugFlag { get; set; } + [ArgDescription("Installs and restores packages which are specified in packages.config")] [ArgShortcut("install")] public string Install { get; set; } + [ArgDescription("Restores installed packages, making them ready for using by the script")] [ArgShortcut("restore")] public bool Restore { get; set; } + [ArgDescription("Cleans installed packages from working directory")] [ArgShortcut("clean")] public bool Clean { get; set; } + [ArgDescription("Allows installation of packages' prelease versions")] [ArgShortcut("pre")] public bool AllowPreReleaseFlag { get; set; } From 2ec5681a3efc6d52ce605b96c0d84b15626e7da4 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 6 Apr 2013 12:43:39 -0700 Subject: [PATCH 0173/1224] Fixing logic to load script packs from the bin folder --- src/ScriptCs/CompositionRoot.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index e7a5daf3..522bc322 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.Composition.Hosting; +using System.IO; using Autofac; using Autofac.Integration.Mef; using ScriptCs.Engine.Roslyn; @@ -12,6 +13,7 @@ public class CompositionRoot { private readonly bool _debug; private IContainer _container; + private ScriptServiceRoot _scriptServiceRoot; public CompositionRoot(bool debug) { @@ -47,15 +49,19 @@ public void Initialize() } builder.RegisterType().As(); - - var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory, "*.pack.dll"); - builder.RegisterComposablePartCatalog(catalog); + var scriptPath = Environment.CurrentDirectory; + if (Directory.Exists(scriptPath)) + { + var catalog = new DirectoryCatalog(Path.Combine(Environment.CurrentDirectory, "bin")); + builder.RegisterComposablePartCatalog(catalog); + } _container = builder.Build(); + _scriptServiceRoot = _container.Resolve(); } public ScriptServiceRoot GetServiceRoot() { - return _container.Resolve(); + return _scriptServiceRoot; } } } \ No newline at end of file From 45766bb5c72c79bf6d9b8e5fb5fd99c28cf69b3d Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 6 Apr 2013 12:46:31 -0700 Subject: [PATCH 0174/1224] fix --- src/ScriptCs/CompositionRoot.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 522bc322..225609a8 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -49,10 +49,10 @@ public void Initialize() } builder.RegisterType().As(); - var scriptPath = Environment.CurrentDirectory; + var scriptPath = Path.Combine(Environment.CurrentDirectory, "bin") ; if (Directory.Exists(scriptPath)) { - var catalog = new DirectoryCatalog(Path.Combine(Environment.CurrentDirectory, "bin")); + var catalog = new DirectoryCatalog(scriptPath); builder.RegisterComposablePartCatalog(catalog); } _container = builder.Build(); From 7a1a1e306021256f6a7422d979759fd8e1b1021a Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 6 Apr 2013 15:10:33 -0700 Subject: [PATCH 0175/1224] Cleaning up script packs, adding the script pack context namespace, and adding unit tests --- src/ScriptCs.Core/ScriptExecutor.cs | 1 + src/ScriptCs.Core/ScriptPackSession.cs | 21 ++- .../RoslynScriptEngine.cs | 3 +- .../ScriptCs.Core.Tests.csproj | 1 + .../ScriptPackSessionTests.cs | 142 ++++++++++++++++++ 5 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 test/ScriptCs.Core.Tests/ScriptPackSessionTests.cs diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index ab28988b..6f604bc4 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -31,6 +31,7 @@ public void Execute(string script, IEnumerable paths, IEnumerable _scriptPacks; + private readonly IEnumerable _contexts; private IList _references; private IList _namespaces; - + public ScriptPackSession(IEnumerable scriptPacks) { _scriptPacks = scriptPacks; - + _contexts = _scriptPacks.Select(x => x.GetContext()); _references = new List(); _namespaces = new List(); + + AddScriptContextNamespace(); } - public IEnumerable ScriptPacks + private void AddScriptContextNamespace() { - get { return _scriptPacks; } + foreach (var context in _contexts) + { + _namespaces.Add(context.GetType().Namespace); + } } + public IEnumerable Contexts + { + get { return _contexts; } + } + public IEnumerable References { get { return _references; } diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index dc4c92d6..c72b003b 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -25,8 +25,7 @@ public string BaseDirectory public void Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { - var contexts = scriptPackSession.ScriptPacks.Select(x => x.GetContext()); - var host = _scriptHostFactory.CreateScriptHost(new ScriptPackManager(contexts)); + var host = _scriptHostFactory.CreateScriptHost(new ScriptPackManager(scriptPackSession.Contexts)); var session = _scriptEngine.CreateSession(host); diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 2cbe88d7..160694d4 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -40,6 +40,7 @@ + diff --git a/test/ScriptCs.Core.Tests/ScriptPackSessionTests.cs b/test/ScriptCs.Core.Tests/ScriptPackSessionTests.cs new file mode 100644 index 00000000..33071f15 --- /dev/null +++ b/test/ScriptCs.Core.Tests/ScriptPackSessionTests.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Contracts; +using Xunit; +using Should; +using Moq; + +namespace ScriptCs.Tests +{ + public class ScriptPackSessionTests + { + public class TheConstructor + { + private ScriptPackSession _scriptPackSession; + private Mock _scriptPackMock; + private Mock _contextMock; + + public TheConstructor() + { + _scriptPackMock = new Mock(); + _contextMock = new Mock(); + _scriptPackMock.Setup(p => p.GetContext()).Returns(_contextMock.Object); + _scriptPackSession = new ScriptPackSession(new List{_scriptPackMock.Object}); + } + + [Fact] + public void ShouldPopulateContexts() + { + _scriptPackSession.Contexts.ShouldContain(_contextMock.Object); + } + + [Fact] + public void ShouldInitializeReferences() + { + _scriptPackSession.References.ShouldNotBeNull(); + } + + [Fact] + public void ShouldInitializeNamespaces() + { + _scriptPackSession.Namespaces.ShouldNotBeNull(); + } + + [Fact] + public void ShouldAddContextNamespaces() + { + _scriptPackSession.Namespaces.Contains(_contextMock.Object.GetType().Namespace); + } + + } + + public class TheInitializeMethod + { + private ScriptPackSession _scriptPackSession; + private Mock _scriptPackMock1; + private Mock _scriptPackMock2; + private Mock _contextMock1; + private Mock _contextMock2; + + public TheInitializeMethod() + { + _contextMock1 = new Mock(); + _contextMock2 = new Mock(); + _scriptPackMock1 = new Mock(); + _scriptPackMock1.Setup(p => p.GetContext()).Returns(_contextMock1.Object); + _scriptPackMock2 = new Mock(); + _scriptPackMock2.Setup(p => p.GetContext()).Returns(_contextMock2.Object); + _scriptPackSession = new ScriptPackSession(new List { _scriptPackMock1.Object, _scriptPackMock2.Object }); + _scriptPackSession.InitializePacks(); + } + + [Fact] + public void ShouldCallInitializeOnAllScriptPacks() + { + _scriptPackMock1.Verify(p=>p.Initialize(_scriptPackSession)); + _scriptPackMock2.Verify(p =>p.Initialize(_scriptPackSession)); + } + } + + public class TheTerminateMethod + { + private ScriptPackSession _scriptPackSession; + private Mock _scriptPackMock1; + private Mock _scriptPackMock2; + private Mock _contextMock1; + private Mock _contextMock2; + + public TheTerminateMethod() + { + _contextMock1 = new Mock(); + _contextMock2 = new Mock(); + _scriptPackMock1 = new Mock(); + _scriptPackMock1.Setup(p => p.GetContext()).Returns(_contextMock1.Object); + _scriptPackMock2 = new Mock(); + _scriptPackMock2.Setup(p => p.GetContext()).Returns(_contextMock2.Object); + _scriptPackSession = new ScriptPackSession(new List { _scriptPackMock1.Object, _scriptPackMock2.Object }); + _scriptPackSession.TerminatePacks(); + } + + [Fact] + public void ShouldCallTerminateOnAllScriptPacks() + { + _scriptPackMock1.Verify(p => p.Terminate()); + _scriptPackMock2.Verify(p => p.Terminate()); + } + } + + public class TheAddReferenceMethod + { + private ScriptPackSession _scriptPackSession = new ScriptPackSession(Enumerable.Empty()); + + public TheAddReferenceMethod() + { + ((IScriptPackSession)_scriptPackSession).AddReference("ref"); + } + + [Fact] + public void ShouldAddTheReference() + { + _scriptPackSession.References.ShouldContain("ref"); + } + } + + public class TheImportNamespaceMethod + { + private ScriptPackSession _scriptPackSession = new ScriptPackSession(Enumerable.Empty()); + + public TheImportNamespaceMethod() + { + ((IScriptPackSession)_scriptPackSession).ImportNamespace("ns"); + } + + public void ShouldAddTheNamespace() + { + _scriptPackSession.Namespaces.ShouldContain("ns"); + } + } + } +} From 929723201c456950a5a41759c9c22880f466536a Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 6 Apr 2013 16:23:14 -0700 Subject: [PATCH 0176/1224] Moving ScriptHost and ScriptHostFactory back to ScriptCs as there is nothing Roslyn specific. Adding ScriptCs.Core to default script references --- src/ScriptCs.Core/ScriptCs.Core.csproj | 3 ++ .../IScriptHostFactory.cs | 11 ------ .../RoslynScriptEngine.cs | 2 +- .../ScriptCs.Engine.Roslyn.csproj | 3 -- src/ScriptCs.Engine.Roslyn/ScriptHost.cs | 22 ------------ .../ScriptHostFactory.cs | 13 ------- .../ScriptCs.Core.Tests.csproj | 1 + .../ScriptCs.Engine.Roslyn.Tests.csproj | 1 - .../ScriptHostTests.cs | 36 ------------------- 9 files changed, 5 insertions(+), 87 deletions(-) delete mode 100644 src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs delete mode 100644 src/ScriptCs.Engine.Roslyn/ScriptHost.cs delete mode 100644 src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs delete mode 100644 test/ScriptCs.Engine.Roslyn.Tests/ScriptHostTests.cs diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 891f53a0..c194f62d 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -47,6 +47,7 @@ + @@ -63,6 +64,8 @@ + + diff --git a/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs b/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs deleted file mode 100644 index 5c7a71b2..00000000 --- a/src/ScriptCs.Engine.Roslyn/IScriptHostFactory.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -using ScriptCs.Contracts; - -namespace ScriptCs.Engine.Roslyn -{ - public interface IScriptHostFactory - { - ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager); - } -} diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index c72b003b..61273397 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -13,7 +13,7 @@ public class RoslynScriptEngine : IScriptEngine public RoslynScriptEngine(IScriptHostFactory scriptHostFactory) { _scriptEngine = new ScriptEngine(); - + _scriptEngine.AddReference(typeof(ScriptExecutor).Assembly); _scriptHostFactory = scriptHostFactory; } diff --git a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj index 38a08ea6..e6277a1f 100644 --- a/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj +++ b/src/ScriptCs.Engine.Roslyn/ScriptCs.Engine.Roslyn.csproj @@ -30,12 +30,9 @@ Properties\CommonVersionInfo.cs - - - diff --git a/src/ScriptCs.Engine.Roslyn/ScriptHost.cs b/src/ScriptCs.Engine.Roslyn/ScriptHost.cs deleted file mode 100644 index cc54563a..00000000 --- a/src/ScriptCs.Engine.Roslyn/ScriptHost.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -using ScriptCs.Contracts; - -namespace ScriptCs.Engine.Roslyn -{ - public class ScriptHost - { - private IScriptPackManager _scriptPackManager; - - public ScriptHost(IScriptPackManager scriptPackManager) - { - _scriptPackManager = scriptPackManager; - } - - public T Get() where T:IScriptPackContext - { - return _scriptPackManager.Get(); - } - - } -} diff --git a/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs b/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs deleted file mode 100644 index 0d8c84bd..00000000 --- a/src/ScriptCs.Engine.Roslyn/ScriptHostFactory.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using ScriptCs.Contracts; - -namespace ScriptCs.Engine.Roslyn -{ - public class ScriptHostFactory : IScriptHostFactory - { - public ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager) - { - return new ScriptHost(scriptPackManager); - } - } -} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 160694d4..7f382aea 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -39,6 +39,7 @@ + diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj index 433257b4..4f9bc964 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj +++ b/test/ScriptCs.Engine.Roslyn.Tests/ScriptCs.Engine.Roslyn.Tests.csproj @@ -42,7 +42,6 @@ - diff --git a/test/ScriptCs.Engine.Roslyn.Tests/ScriptHostTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/ScriptHostTests.cs deleted file mode 100644 index 97f2ab8c..00000000 --- a/test/ScriptCs.Engine.Roslyn.Tests/ScriptHostTests.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ScriptCs.Contracts; -using ScriptCs.Engine.Roslyn; -using Xunit; -using Should; -using Moq; - -namespace ScriptCs.Tests -{ - public class ScriptHostTests - { - public class TheGetMethod - { - private Mock _mockContext = new Mock(); - private Mock _mockScriptPackManager = new Mock(); - private ScriptHost _scriptHost; - - public TheGetMethod() - { - _scriptHost = new ScriptHost(_mockScriptPackManager.Object); - _mockScriptPackManager.Setup(s => s.Get()).Returns(_mockContext.Object); - } - - [Fact] - public void ShoulGetScriptPackFromScriptPackManagerWhenInvoked() - { - var result = _scriptHost.Get(); - _mockScriptPackManager.Verify(s=>s.Get()); - } - } - } -} From dac5b4716c4e4b58be2346d45838dff8f66a25e1 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 6 Apr 2013 16:27:42 -0700 Subject: [PATCH 0177/1224] adding moved and deleted files, and renaming Get to Require --- src/ScriptCs.Core/IScriptHostFactory.cs | 11 +++++++ src/ScriptCs.Core/ScriptHost.cs | 22 +++++++++++++ src/ScriptCs.Core/ScriptHostFactory.cs | 13 ++++++++ test/ScriptCs.Core.Tests/ScriptHostTests.cs | 36 +++++++++++++++++++++ 4 files changed, 82 insertions(+) create mode 100644 src/ScriptCs.Core/IScriptHostFactory.cs create mode 100644 src/ScriptCs.Core/ScriptHost.cs create mode 100644 src/ScriptCs.Core/ScriptHostFactory.cs create mode 100644 test/ScriptCs.Core.Tests/ScriptHostTests.cs diff --git a/src/ScriptCs.Core/IScriptHostFactory.cs b/src/ScriptCs.Core/IScriptHostFactory.cs new file mode 100644 index 00000000..469e8068 --- /dev/null +++ b/src/ScriptCs.Core/IScriptHostFactory.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public interface IScriptHostFactory + { + ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager); + } +} diff --git a/src/ScriptCs.Core/ScriptHost.cs b/src/ScriptCs.Core/ScriptHost.cs new file mode 100644 index 00000000..27f16feb --- /dev/null +++ b/src/ScriptCs.Core/ScriptHost.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public class ScriptHost + { + private IScriptPackManager _scriptPackManager; + + public ScriptHost(IScriptPackManager scriptPackManager) + { + _scriptPackManager = scriptPackManager; + } + + public T Require() where T:IScriptPackContext + { + return _scriptPackManager.Get(); + } + + } +} diff --git a/src/ScriptCs.Core/ScriptHostFactory.cs b/src/ScriptCs.Core/ScriptHostFactory.cs new file mode 100644 index 00000000..c2b86317 --- /dev/null +++ b/src/ScriptCs.Core/ScriptHostFactory.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public class ScriptHostFactory : IScriptHostFactory + { + public ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager) + { + return new ScriptHost(scriptPackManager); + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptHostTests.cs b/test/ScriptCs.Core.Tests/ScriptHostTests.cs new file mode 100644 index 00000000..4f03b375 --- /dev/null +++ b/test/ScriptCs.Core.Tests/ScriptHostTests.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Contracts; +using ScriptCs; +using Xunit; +using Should; +using Moq; + +namespace ScriptCs.Tests +{ + public class ScriptHostTests + { + public class TheGetMethod + { + private Mock _mockContext = new Mock(); + private Mock _mockScriptPackManager = new Mock(); + private ScriptHost _scriptHost; + + public TheGetMethod() + { + _scriptHost = new ScriptHost(_mockScriptPackManager.Object); + _mockScriptPackManager.Setup(s => s.Get()).Returns(_mockContext.Object); + } + + [Fact] + public void ShoulGetScriptPackFromScriptPackManagerWhenInvoked() + { + var result = _scriptHost.Require(); + _mockScriptPackManager.Verify(s=>s.Get()); + } + } + } +} From ece50ad159b98759d6f16914068320318ccffbf9 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 6 Apr 2013 23:15:50 -0400 Subject: [PATCH 0178/1224] issue #169 - added Save command --- src/ScriptCs.Core/IPackageAssemblyResolver.cs | 1 + .../Package/IPackageContainer.cs | 1 + src/ScriptCs.Core/Package/PackageContainer.cs | 16 ++++++++++ src/ScriptCs.Core/PackageAssemblyResolver.cs | 27 +++++++++++++++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 4 ++- src/ScriptCs/Command/CommandFactory.cs | 10 +++++++ src/ScriptCs/Command/ICommand.cs | 2 ++ src/ScriptCs/Command/SaveCommand.cs | 29 +++++++++++++++++++ src/ScriptCs/ScriptCs.csproj | 2 ++ src/ScriptCs/ScriptCsArgs.cs | 10 ++++--- 10 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/ScriptCs/Command/SaveCommand.cs diff --git a/src/ScriptCs.Core/IPackageAssemblyResolver.cs b/src/ScriptCs.Core/IPackageAssemblyResolver.cs index 2c927dab..14fe7496 100644 --- a/src/ScriptCs.Core/IPackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/IPackageAssemblyResolver.cs @@ -6,6 +6,7 @@ namespace ScriptCs { public interface IPackageAssemblyResolver { + void SavePackages(Action output); IEnumerable GetPackages(string workingDirectory); IEnumerable GetAssemblyNames(string workingDirectory, Action outputCallback = null); } diff --git a/src/ScriptCs.Core/Package/IPackageContainer.cs b/src/ScriptCs.Core/Package/IPackageContainer.cs index 2866e49b..a912dc5d 100644 --- a/src/ScriptCs.Core/Package/IPackageContainer.cs +++ b/src/ScriptCs.Core/Package/IPackageContainer.cs @@ -4,6 +4,7 @@ namespace ScriptCs.Package { public interface IPackageContainer { + IEnumerable CreatePackageFile(); IEnumerable FindReferences(string path); IPackageObject FindPackage(string path, IPackageReference packageReference); } diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index a1f9fb57..f4e41297 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -14,6 +14,22 @@ public PackageContainer(IFileSystem fileSystem) _fileSystem = fileSystem; } + public IEnumerable CreatePackageFile() + { + var packageReferenceFile = new PackageReferenceFile(Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFile)); + var repository = new LocalPackageRepository(Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFolder)); + var arbitraryPackages = repository.GetPackages(); + var result = new List(); + + foreach (var package in arbitraryPackages) + { + packageReferenceFile.AddEntry(package.Id, package.Version, VersionUtility.ParseFrameworkName("net45")); + result.Add(string.Format("{0}, Version {1}, .NET 4.5", package.Id, package.Version)); + } + + return result; + } + public IPackageObject FindPackage(string path, IPackageReference packageRef) { var repository = new LocalPackageRepository(path); diff --git a/src/ScriptCs.Core/PackageAssemblyResolver.cs b/src/ScriptCs.Core/PackageAssemblyResolver.cs index ee9d9f39..553377bb 100644 --- a/src/ScriptCs.Core/PackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/PackageAssemblyResolver.cs @@ -21,6 +21,33 @@ public PackageAssemblyResolver(IFileSystem fileSystem, IPackageContainer package _packageContainer = packageContainer; } + public void SavePackages(Action output) + { + var packagesFile = Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFile); + var packagesFolder = Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFolder); + + if (_fileSystem.FileExists(packagesFile)) + { + output("Packages.config already exists!"); + return; + } + + if (!_fileSystem.DirectoryExists(packagesFolder)) + { + output("Packages directory does not exist!"); + return; + } + + var result = _packageContainer.CreatePackageFile().ToList(); + if (!result.Any()) + { + output("No packages found!"); + } + + result.ForEach(i => output(string.Format("Added {0}", i))); + output("Packages.config successfully created!"); + } + public IEnumerable GetPackages(string workingDirectory) { var packageFile = Path.Combine(workingDirectory, Constants.PackagesFile); diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 123eb7fe..29b7275c 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -68,7 +68,9 @@ - + + Designer + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index c8cf35cf..9fb621e0 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -59,6 +59,16 @@ public ICommand CreateCommand(ScriptCsArgs args) return cleanCommand; } + if (args.Save) + { + return new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + } + + if (args.Version) + { + return new VersionCommand(); + } + return new InvalidCommand(); } } diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index 171064b8..62dbfcb6 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -6,6 +6,8 @@ public interface IScriptCommand : ICommand { } public interface IRestoreCommand : ICommand { } + public interface ISaveCommand : ICommand { } + public interface ICleanCommand : ICommand { } public interface IInstallCommand : ICommand { } diff --git a/src/ScriptCs/Command/SaveCommand.cs b/src/ScriptCs/Command/SaveCommand.cs new file mode 100644 index 00000000..71cffd49 --- /dev/null +++ b/src/ScriptCs/Command/SaveCommand.cs @@ -0,0 +1,29 @@ +using System; + +namespace ScriptCs.Command +{ + internal class SaveCommand : ISaveCommand + { + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + + public SaveCommand(IPackageAssemblyResolver packageAssemblyResolver) + { + _packageAssemblyResolver = packageAssemblyResolver; + } + + public CommandResult Execute() + { + Console.WriteLine("Initiated saving packages into packages.config..."); + try + { + _packageAssemblyResolver.SavePackages(msg => Console.WriteLine(msg)); + } + catch (Exception e) + { + Console.WriteLine("Save failed: {0}.", e.Message); + return CommandResult.Error; + } + return CommandResult.Success; + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index f88fc724..1876f56a 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -48,6 +48,8 @@ + + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 7b65efac..24d99774 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -18,15 +18,17 @@ public class ScriptCsArgs [ArgShortcut("restore")] public bool Restore { get; set; } + [ArgShortcut("save")] + public bool Save { get; set; } + + [ArgDescription("Cleans installed packages from working directory")] [ArgShortcut("clean")] public bool Clean { get; set; } [ArgShortcut("pre")] public bool AllowPreReleaseFlag { get; set; } - public bool IsValid() - { - return !string.IsNullOrWhiteSpace(ScriptName) || Install != null; - } + [ArgDescription("Outputs version information")] + public bool Version { get; set; } } } \ No newline at end of file From 4214396113b66f77ccb2431bd746bf536effd964 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 6 Apr 2013 23:16:09 -0400 Subject: [PATCH 0179/1224] added tests for #169 --- .../PackageAssemblyResolverTests.cs | 83 +++++++++++++++++++ test/ScriptCs.Tests/CommandFactoryTests.cs | 12 +++ 2 files changed, 95 insertions(+) diff --git a/test/ScriptCs.Core.Tests/PackageAssemblyResolverTests.cs b/test/ScriptCs.Core.Tests/PackageAssemblyResolverTests.cs index 6c624640..4748be7e 100644 --- a/test/ScriptCs.Core.Tests/PackageAssemblyResolverTests.cs +++ b/test/ScriptCs.Core.Tests/PackageAssemblyResolverTests.cs @@ -292,5 +292,88 @@ public void ShouldGetReferencesToPackages() result.Count().ShouldEqual(1); } } + + public class SavePackagesMethod + { + private Mock _fs; + private Mock _pc; + + public SavePackagesMethod() + { + _fs = new Mock(); + _pc = new Mock(); + } + + private IPackageAssemblyResolver GetResolver() + { + return new PackageAssemblyResolver(_fs.Object, _pc.Object); + } + + [Fact] + public void ShouldNotSaveWhenThereIsPackagesFile() + { + _fs.Setup(i => i.CurrentDirectory).Returns("C:/"); + _fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); + _fs.Setup(i => i.DirectoryExists(It.IsAny())).Returns(true); + var resolver = GetResolver(); + var output = new List(); + + resolver.SavePackages(msg => output.Add(msg)); + + _pc.Verify(i => i.CreatePackageFile(), Times.Never()); + output.ShouldContain("Packages.config already exists!"); + } + + [Fact] + public void ShouldNotSaveWhenThereIsNoPackagesFolder() + { + _fs.Setup(i => i.CurrentDirectory).Returns("C:/"); + _fs.Setup(i => i.FileExists(It.IsAny())).Returns(false); + _fs.Setup(i => i.DirectoryExists(It.IsAny())).Returns(false); + var resolver = GetResolver(); + + var output = new List(); + + resolver.SavePackages(msg => output.Add(msg)); + + _pc.Verify(i => i.CreatePackageFile(), Times.Never()); + output.ShouldContain("Packages directory does not exist!"); + } + + [Fact] + public void ShouldSaveWhenThereIsNoPackagesConfigAndThereIsPackagesFolder() + { + _fs.Setup(i => i.CurrentDirectory).Returns("C:/"); + _fs.Setup(i => i.FileExists(It.IsAny())).Returns(false); + _fs.Setup(i => i.DirectoryExists(It.IsAny())).Returns(true); + _pc.Setup(i => i.CreatePackageFile()).Returns(new List {"package"}); + var resolver = GetResolver(); + + var output = new List(); + + resolver.SavePackages(msg => output.Add(msg)); + + _pc.Verify(i => i.CreatePackageFile(), Times.Once()); + output.ShouldContain("Packages.config successfully created!"); + output.ShouldContain("Added package"); + } + + [Fact] + public void ShouldDisplayErrorWhenNoPackagesFound() + { + _fs.Setup(i => i.CurrentDirectory).Returns("C:/"); + _fs.Setup(i => i.FileExists(It.IsAny())).Returns(false); + _fs.Setup(i => i.DirectoryExists(It.IsAny())).Returns(true); + _pc.Setup(i => i.CreatePackageFile()).Returns(new List()); + var resolver = GetResolver(); + + var output = new List(); + + resolver.SavePackages(msg => output.Add(msg)); + + _pc.Verify(i => i.CreatePackageFile(), Times.Once()); + output.ShouldContain("No packages found!"); + } + } } } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 9657e96b..f0ee8d27 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -101,6 +101,18 @@ public void ShouldCleanWhenCleanFlagIsPassed() result.ShouldImplement(); } + [Fact] + public void ShouldSaveWhenSaveFlagIsPassed() + { + var args = new ScriptCsArgs { Save = true, ScriptName = null }; + + var factory = new CommandFactory(CreateRoot()); + var result = factory.CreateCommand(args); + + result.ShouldNotBeNull(); + result.ShouldImplement(); + } + [Fact] public void ShouldReturnInvalidWhenNoNameOrInstallSet() { From 99f468c3819ee7c57797cb56b063ed2be4b319cd Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 6 Apr 2013 21:24:02 -0700 Subject: [PATCH 0180/1224] Adding to filter out adding null contexts --- src/ScriptCs.Core/ScriptPackSession.cs | 2 +- src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs | 3 ++- .../RoslynScriptEngineTests.cs | 7 +++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ScriptCs.Core/ScriptPackSession.cs b/src/ScriptCs.Core/ScriptPackSession.cs index 1704ad65..52046bf9 100644 --- a/src/ScriptCs.Core/ScriptPackSession.cs +++ b/src/ScriptCs.Core/ScriptPackSession.cs @@ -16,7 +16,7 @@ public class ScriptPackSession : IScriptPackSession public ScriptPackSession(IEnumerable scriptPacks) { _scriptPacks = scriptPacks; - _contexts = _scriptPacks.Select(x => x.GetContext()); + _contexts = _scriptPacks.Select(s => s.GetContext()).Where(c=>c != null); _references = new List(); _namespaces = new List(); diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 61273397..65e91717 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Reflection; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; @@ -26,7 +27,7 @@ public string BaseDirectory public void Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { var host = _scriptHostFactory.CreateScriptHost(new ScriptPackManager(scriptPackSession.Contexts)); - + var session = _scriptEngine.CreateSession(host); foreach (var reference in references.Union(scriptPackSession.References).Distinct()) diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 75e6ff89..937cbac4 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -36,18 +36,17 @@ public void ShouldCreateScriptHostWithContexts() var code = "var a = 0;"; var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); - + var scriptPack1 = new Mock(); scriptPack1.Setup(p => p.Initialize(It.IsAny())); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + scriptPack1.Setup(p => p.GetContext()).Returns((IScriptPackContext)null); var scriptPackSession = new ScriptPackSession(new[] { scriptPack1.Object }); - + engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny())); } - } } } \ No newline at end of file From 51150f776f2255e2d061224ffa6aa5f0356db6e4 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 7 Apr 2013 11:30:24 -0400 Subject: [PATCH 0181/1224] added grouping to get latest versions only --- src/ScriptCs.Core/Package/PackageContainer.cs | 7 ++++--- src/ScriptCs.Core/PackageAssemblyResolver.cs | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index f4e41297..8b23f484 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -21,10 +21,11 @@ public IEnumerable CreatePackageFile() var arbitraryPackages = repository.GetPackages(); var result = new List(); - foreach (var package in arbitraryPackages) + foreach (var package in arbitraryPackages.GroupBy(i => i.Id)) { - packageReferenceFile.AddEntry(package.Id, package.Version, VersionUtility.ParseFrameworkName("net45")); - result.Add(string.Format("{0}, Version {1}, .NET 4.5", package.Id, package.Version)); + var p = package.OrderByDescending(i => i.Version).FirstOrDefault(); + packageReferenceFile.AddEntry(p.Id, p.Version, VersionUtility.ParseFrameworkName("net45")); + result.Add(string.Format("{0}, Version {1}, .NET 4.5", p.Id, p.Version)); } return result; diff --git a/src/ScriptCs.Core/PackageAssemblyResolver.cs b/src/ScriptCs.Core/PackageAssemblyResolver.cs index 553377bb..658970a8 100644 --- a/src/ScriptCs.Core/PackageAssemblyResolver.cs +++ b/src/ScriptCs.Core/PackageAssemblyResolver.cs @@ -42,6 +42,7 @@ public void SavePackages(Action output) if (!result.Any()) { output("No packages found!"); + return; } result.ForEach(i => output(string.Format("Added {0}", i))); From 0b682b39b9295ee22e9556443791cf5db3cb27a4 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 7 Apr 2013 12:02:40 -0400 Subject: [PATCH 0182/1224] added args description --- src/ScriptCs/ScriptCsArgs.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 87e3e278..1a0fb1ab 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -21,6 +21,7 @@ public class ScriptCsArgs [ArgShortcut("restore")] public bool Restore { get; set; } + [ArgDescription("Creates a packages.config file based on the packages directory")] [ArgShortcut("save")] public bool Save { get; set; } From 0dd8c99796b955eec7e8a389c09d8477bc23a1ad Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Mon, 8 Apr 2013 11:12:59 -0300 Subject: [PATCH 0183/1224] # Updated ScriptCsArgs.cs --- src/ScriptCs/ScriptCsArgs.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 4450a076..0e5168ec 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -11,8 +11,7 @@ namespace ScriptCs public class ScriptCsArgs { - private const string ValidLogLevels = - "off, debug, emergency, fatal, alert, critical, severe, error, warn, notice, info, debug, fine, trace, verbose"; + private const string ValidLogLevels = "error, info, debug, trace"; private string _logLevel; @@ -26,7 +25,7 @@ public class ScriptCsArgs [ArgDescription("Flag which defines the log level used. Possible values:" + ValidLogLevels)] [ArgShortcut("log")] - [DefaultValue("off")] + [DefaultValue("info")] public string LogLevel { get @@ -62,6 +61,11 @@ public bool IsValid() private bool IsLogLevelValid() { + if (!ValidLogLevels.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Contains(LogLevel)) + { + return false; + } + var repository = LogManager.GetRepository(); var levelMap = repository.LevelMap; return levelMap From 827568ab9c5bc8549e1ef565973dd2a9fccd31f9 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Mon, 8 Apr 2013 11:44:12 -0300 Subject: [PATCH 0184/1224] # Updated logging messages --- src/ScriptCs.Core/ScriptExecutor.cs | 4 ++++ .../RoslynScriptDebuggerEngine.cs | 4 ++++ src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs | 8 +++++--- src/ScriptCs/Command/CleanCommand.cs | 10 ++++++++++ src/ScriptCs/Command/ExecuteScriptCommand.cs | 2 +- 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index b93d6151..d809998b 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -38,10 +38,14 @@ public void Execute(string script, IEnumerable paths, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { + _logger.Info("Starting to create execution components"); _logger.Debug("Creating script host"); var host = _scriptHostFactory.CreateScriptHost(new ScriptPackManager(scriptPackSession.Contexts)); _logger.Debug("Creating session"); @@ -36,18 +37,19 @@ public void Execute(string code, IEnumerable references, IEnumerable GetAssemblyPaths(string workingDirectory) var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll").ToList(); foreach (var path in assemblyPaths.Select(Path.GetFileName)) { - _logger.InfoFormat("Found assembly reference: {0}", path); + _logger.DebugFormat("Found assembly reference: {0}", path); } return assemblyPaths; From 578b9b91c493633f94964d40c1a75c0d4db92b8e Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 8 Apr 2013 20:13:36 -0400 Subject: [PATCH 0185/1224] Update version to v0.3.0 --- build/ScriptCs.Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 8c18979e..aa729af5 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -9,7 +9,7 @@ - alpha + From 375f5b3a91a0b63a9dfb0b30fc896f8ad5058b67 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 8 Apr 2013 20:14:59 -0400 Subject: [PATCH 0186/1224] Update version to v0.4.0-alpha --- build/ScriptCs.Version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index aa729af5..c4a3e643 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -4,12 +4,12 @@ 0 - 3 + 4 0 - + alpha From c7b49d6b153c54d096c5ef41ffa487cca734a567 Mon Sep 17 00:00:00 2001 From: ianbattersby Date: Sun, 7 Apr 2013 21:09:16 +0100 Subject: [PATCH 0187/1224] Adding EXEs as valid assemblies. --- src/ScriptCs.Core/Package/PackageObject.cs | 3 ++- src/ScriptCs/Command/ExecuteScriptCommand.cs | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/Package/PackageObject.cs b/src/ScriptCs.Core/Package/PackageObject.cs index 7c8167d5..4b4b6c66 100644 --- a/src/ScriptCs.Core/Package/PackageObject.cs +++ b/src/ScriptCs.Core/Package/PackageObject.cs @@ -9,6 +9,7 @@ namespace ScriptCs.Package internal class PackageObject : IPackageObject { private const string Dll = ".dll"; + private const string Exe = ".exe"; private readonly IPackage _package; public PackageObject(IPackage package, FrameworkName frameworkName) @@ -45,7 +46,7 @@ public string FullName public IEnumerable GetCompatibleDlls(FrameworkName frameworkName) { - var dlls = _package.GetLibFiles().Where(i => i.EffectivePath.EndsWith(Dll)); + var dlls = _package.GetLibFiles().Where(i => i.EffectivePath.EndsWith(Dll) || i.EffectivePath.EndsWith(Exe)); IEnumerable compatibleFiles; VersionUtility.TryGetCompatibleItems(frameworkName, dlls, out compatibleFiles); diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 733f8d18..0d60a292 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -49,7 +49,11 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) if (!_fileSystem.DirectoryExists(binFolder)) _fileSystem.CreateDirectory(binFolder); - var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll").ToList(); + var assemblyPaths = + _fileSystem.EnumerateFiles(binFolder, "*.dll") + .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) + .ToList(); + foreach (var path in assemblyPaths.Select(Path.GetFileName)) { Console.WriteLine("Found assembly reference: " + path); From 11845b98a710e684571d6c4c077543c4cd409162 Mon Sep 17 00:00:00 2001 From: ianbattersby Date: Tue, 9 Apr 2013 21:20:08 +0100 Subject: [PATCH 0188/1224] Updated Autofac/MEF integration to 3.0.1 (resolving issue outlined in #182). --- src/ScriptCs.Core/ScriptCs.Core.csproj | 15 +++++++++------ src/ScriptCs.Core/packages.config | 4 ++-- src/ScriptCs/ScriptCs.csproj | 12 +++++++----- src/ScriptCs/packages.config | 3 ++- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 4b9b932a..b2aec963 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -9,14 +9,17 @@ ..\..\ - - ..\..\packages\Autofac.3.0.1\lib\net40\Autofac.dll + + False + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.dll - - ..\..\packages\Autofac.3.0.1\lib\net40\Autofac.Configuration.dll + + False + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.Configuration.dll - - ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll + + False + ..\..\packages\Autofac.Mef.3.0.1\lib\net40\Autofac.Integration.Mef.dll False diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 2c44436d..b685c226 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -1,6 +1,6 @@  - - + + \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 6367720d..f5ba8f09 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -12,14 +12,16 @@ ..\..\common\Icon.ico - - ..\..\packages\Autofac.3.0.1\lib\net40\Autofac.dll + + False + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.dll - - ..\..\packages\Autofac.3.0.1\lib\net40\Autofac.Configuration.dll + + False + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.Configuration.dll - ..\..\packages\Autofac.Mef.3.0.0\lib\net40\Autofac.Integration.Mef.dll + ..\..\packages\Autofac.Mef.3.0.1\lib\net40\Autofac.Integration.Mef.dll False diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index b185dba1..9ef6e315 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -1,5 +1,6 @@  - + + \ No newline at end of file From d012034be3e3e2a9c7f42423ce0bb06bdf93a99c Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 10 Apr 2013 01:49:07 +0200 Subject: [PATCH 0189/1224] Made PackageContainer pick the newest supported framework for the packages. Could fix #185 --- src/ScriptCs.Core/Package/PackageContainer.cs | 73 ++++++++++--------- src/ScriptCs.Core/Package/PackageReference.cs | 7 ++ 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index 8b23f484..9eef9d70 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.Versioning; + using NuGet; namespace ScriptCs.Package @@ -16,33 +18,31 @@ public PackageContainer(IFileSystem fileSystem) public IEnumerable CreatePackageFile() { - var packageReferenceFile = new PackageReferenceFile(Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFile)); - var repository = new LocalPackageRepository(Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFolder)); - var arbitraryPackages = repository.GetPackages(); - var result = new List(); + var packagesFile = Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFile); + var packageReferenceFile = new PackageReferenceFile(packagesFile); + + var packagesFolder = Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFolder); + var repository = new LocalPackageRepository(packagesFolder); + + var newestPackages = repository.GetPackages().GroupBy(p => p.Id) + .Select(g => g.OrderByDescending(p => p.Version).FirstOrDefault()); - foreach (var package in arbitraryPackages.GroupBy(i => i.Id)) + foreach (var package in newestPackages) { - var p = package.OrderByDescending(i => i.Version).FirstOrDefault(); - packageReferenceFile.AddEntry(p.Id, p.Version, VersionUtility.ParseFrameworkName("net45")); - result.Add(string.Format("{0}, Version {1}, .NET 4.5", p.Id, p.Version)); - } + var newestFramework = GetNewestSupportedFramework(package); + packageReferenceFile.AddEntry(package.Id, package.Version, newestFramework); - return result; + yield return string.Format("{0}, Version {1}, .NET {2}", package.Id, package.Version, newestFramework.Version); + } } public IPackageObject FindPackage(string path, IPackageReference packageRef) { var repository = new LocalPackageRepository(path); - IPackage package; - if (packageRef.Version != null) - { - package = repository.FindPackage(packageRef.PackageId, new SemanticVersion(packageRef.Version, packageRef.SpecialVersion), true, true); - } - else - { - package = repository.FindPackage(packageRef.PackageId); - } + + var package = packageRef.Version != null + ? repository.FindPackage(packageRef.PackageId, new SemanticVersion(packageRef.Version, packageRef.SpecialVersion), true, true) + : repository.FindPackage(packageRef.PackageId); return package == null ? null : new PackageObject(package, packageRef.FrameworkName); } @@ -50,26 +50,33 @@ public IPackageObject FindPackage(string path, IPackageReference packageRef) public IEnumerable FindReferences(string path) { var packageReferenceFile = new PackageReferenceFile(path); - var references = packageReferenceFile.GetPackageReferences(); - if (!references.Any()) + var references = packageReferenceFile.GetPackageReferences().ToList(); + if (references.Any()) { - var packagesFolder = Path.Combine(_fileSystem.GetWorkingDirectory(path), Constants.PackagesFolder); - if (_fileSystem.DirectoryExists(packagesFolder)) + return references.Select(i => new PackageReference(i.Id, i.TargetFramework, i.Version.Version, i.Version.SpecialVersion)); + } + + // No packages.config, check packages folder + var packagesFolder = Path.Combine(_fileSystem.GetWorkingDirectory(path), Constants.PackagesFolder); + if (_fileSystem.DirectoryExists(packagesFolder)) + { + var repository = new LocalPackageRepository(packagesFolder); + + var arbitraryPackages = repository.GetPackages(); + if (arbitraryPackages.Any()) { - var repository = new LocalPackageRepository(packagesFolder); - var arbitraryPackages = repository.GetPackages().Where(i => i.GetSupportedFrameworks().Any(x => x.FullName == VersionUtility.ParseFrameworkName("net40").FullName)).ToList(); - if (arbitraryPackages.Any()) - { - return arbitraryPackages.Select(i => new PackageReference(i.Id, VersionUtility.ParseFrameworkName("net40"), i.Version.Version) { SpecialVersion = i.Version.SpecialVersion }); - } + return arbitraryPackages.Select(i => + new PackageReference(i.Id, GetNewestSupportedFramework(i), i.Version.Version, i.Version.SpecialVersion)); } - - return Enumerable.Empty(); } - var packages = references.Select(i => new PackageReference(i.Id, i.TargetFramework, i.Version.Version) { SpecialVersion = i.Version.SpecialVersion }); - return packages; + return Enumerable.Empty(); + } + + private static FrameworkName GetNewestSupportedFramework(IPackage packageMetadata) + { + return packageMetadata.GetSupportedFrameworks().OrderByDescending(x => x.Version).FirstOrDefault(); } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/PackageReference.cs b/src/ScriptCs.Core/Package/PackageReference.cs index a24fb4c4..e41471ad 100644 --- a/src/ScriptCs.Core/Package/PackageReference.cs +++ b/src/ScriptCs.Core/Package/PackageReference.cs @@ -6,15 +6,22 @@ namespace ScriptCs.Package public class PackageReference : IPackageReference { public PackageReference(string packageId, FrameworkName frameworkName, Version version) + : this(packageId, frameworkName, version, null) { } + + public PackageReference(string packageId, FrameworkName frameworkName, Version version, string specialVersion) { FrameworkName = frameworkName; PackageId = packageId; Version = version; + SpecialVersion = specialVersion; } public string PackageId { get; private set; } + public FrameworkName FrameworkName { get; private set; } + public Version Version { get; set; } + public string SpecialVersion { get; set; } } } \ No newline at end of file From a0e494aa3775e74a377a852da90b9c4f227d24fa Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 10 Apr 2013 02:20:58 +0200 Subject: [PATCH 0190/1224] Added filter on .NETFramework --- src/ScriptCs.Core/Package/PackageContainer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index 9eef9d70..c90598fa 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -9,6 +9,8 @@ namespace ScriptCs.Package { public class PackageContainer : IPackageContainer { + private const string DotNetFramework = ".NETFramework"; + private readonly IFileSystem _fileSystem; public PackageContainer(IFileSystem fileSystem) @@ -76,7 +78,10 @@ public IEnumerable FindReferences(string path) private static FrameworkName GetNewestSupportedFramework(IPackage packageMetadata) { - return packageMetadata.GetSupportedFrameworks().OrderByDescending(x => x.Version).FirstOrDefault(); + return packageMetadata.GetSupportedFrameworks() + .Where(x => x.Identifier == DotNetFramework) + .OrderByDescending(x => x.Version) + .FirstOrDefault(); } } } \ No newline at end of file From f0238b5f40773265bffd3e826c00fab1b36afd4c Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 9 Apr 2013 21:57:36 -0400 Subject: [PATCH 0191/1224] Manually specify the dependency version numbers in chocolateyInstall.ps1 --- src/ScriptCs/Properties/chocolateyInstall.ps1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/Properties/chocolateyInstall.ps1 b/src/ScriptCs/Properties/chocolateyInstall.ps1 index 5ab98ff0..bf7e64f3 100644 --- a/src/ScriptCs/Properties/chocolateyInstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyInstall.ps1 @@ -10,7 +10,14 @@ Write-Host "Retrieving NuGet dependencies..." -ForegroundColor DarkYellow - "NuGet.Core","Autofac.Mef","Roslyn.Compilers.CSharp","PowerArgs" | %{ .$nuget install $_ -o $nugetPath -nocache } | Out-Null + $dependencies = @{ + "NuGet.Core" = "2.2.0"; + "Autofac.Mef" = "3.0.0"; + "Roslyn.Compilers.CSharp" = "1.2.20906.2"; + "PowerArgs" = "1.4.0.0"; + } + + $dependencies.GetEnumerator() | %{ .$nuget install $_.Name -version $_.Value -o $nugetPath -nocache } | Out-Null Get-ChildItem $nugetPath -Filter "*.dll" -Recurse | %{ Copy-Item $_.FullName $binPath -Force } Remove-Item $nugetPath -Recurse -Force From ae4a9575e4f2ad38af5c3249201382a42be51ac1 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 9 Apr 2013 21:57:59 -0400 Subject: [PATCH 0192/1224] Increment version number to 0.3.1 --- build/ScriptCs.Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index aa729af5..2644d6a6 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -5,7 +5,7 @@ 0 3 - 0 + 1 From b488610abbdb47bd332e043bb9b3567812e4c5de Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Wed, 10 Apr 2013 11:24:43 +0300 Subject: [PATCH 0193/1224] NuGet PowerArgs package updated. --- src/ScriptCs/ScriptCs.csproj | 4 ++-- src/ScriptCs/packages.config | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index f5ba8f09..48e483c7 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -23,9 +23,9 @@ ..\..\packages\Autofac.Mef.3.0.1\lib\net40\Autofac.Integration.Mef.dll - + False - ..\..\packages\PowerArgs.1.4.0.0\lib\net40\PowerArgs.dll + ..\..\packages\PowerArgs.1.4.1.0\lib\net40\PowerArgs.dll diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index 9ef6e315..737b4e92 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file From 3de6e670e729c396ae7ed488418d8e9625e2e06a Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Wed, 10 Apr 2013 11:25:09 +0300 Subject: [PATCH 0194/1224] Chocolatey install updated to mention new PowerArgs version. --- src/ScriptCs/Properties/chocolateyInstall.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Properties/chocolateyInstall.ps1 b/src/ScriptCs/Properties/chocolateyInstall.ps1 index bf7e64f3..f4ca4243 100644 --- a/src/ScriptCs/Properties/chocolateyInstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyInstall.ps1 @@ -14,7 +14,7 @@ "NuGet.Core" = "2.2.0"; "Autofac.Mef" = "3.0.0"; "Roslyn.Compilers.CSharp" = "1.2.20906.2"; - "PowerArgs" = "1.4.0.0"; + "PowerArgs" = "1.4.1.0"; } $dependencies.GetEnumerator() | %{ .$nuget install $_.Name -version $_.Value -o $nugetPath -nocache } | Out-Null From 5a6b3f66197fc61918bfb6cdcebc7bc5a6373196 Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Wed, 10 Apr 2013 15:57:51 +0300 Subject: [PATCH 0195/1224] Fixes #193. DirectoryCatalog is not initialized if script name isn't passed. --- src/ScriptCs/CompositionRoot.cs | 16 +++++++++++----- src/ScriptCs/Program.cs | 3 ++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 225609a8..d6f268a5 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -12,12 +12,14 @@ namespace ScriptCs public class CompositionRoot { private readonly bool _debug; + private readonly bool _shouldInitDrirectoryCatalog; private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; - public CompositionRoot(bool debug) + public CompositionRoot(bool debug, bool useDirectoryCatalog) { _debug = debug; + _shouldInitDrirectoryCatalog = useDirectoryCatalog; } public void Initialize() @@ -49,11 +51,15 @@ public void Initialize() } builder.RegisterType().As(); - var scriptPath = Path.Combine(Environment.CurrentDirectory, "bin") ; - if (Directory.Exists(scriptPath)) + + if (_shouldInitDrirectoryCatalog) { - var catalog = new DirectoryCatalog(scriptPath); - builder.RegisterComposablePartCatalog(catalog); + var scriptPath = Path.Combine(Environment.CurrentDirectory, "bin"); + if (Directory.Exists(scriptPath)) + { + var catalog = new DirectoryCatalog(scriptPath); + builder.RegisterComposablePartCatalog(catalog); + } } _container = builder.Build(); _scriptServiceRoot = _container.Resolve(); diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index ee76d718..13f49de5 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -31,7 +31,8 @@ private static int Main(string[] args) } var debug = commandArgs.DebugFlag; - var compositionRoot = new CompositionRoot(debug); + var scriptProvided = !string.IsNullOrWhiteSpace(commandArgs.ScriptName); + var compositionRoot = new CompositionRoot(debug, scriptProvided); compositionRoot.Initialize(); var scriptServiceRoot = compositionRoot.GetServiceRoot(); From 73666828a2e833a3f9ee700bec9793cfc217c3f7 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Wed, 10 Apr 2013 11:18:45 -0300 Subject: [PATCH 0196/1224] # Added LogLevel.cs enum to parse args --- src/ScriptCs/CompositionRoot.cs | 4 +-- src/ScriptCs/LogLevel.cs | 10 +++++++ src/ScriptCs/LoggerConfigurator.cs | 13 ++++---- src/ScriptCs/ScriptCs.csproj | 1 + src/ScriptCs/ScriptCsArgs.cs | 48 ++++-------------------------- 5 files changed, 24 insertions(+), 52 deletions(-) create mode 100644 src/ScriptCs/LogLevel.cs diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 2491546e..d86f624c 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -13,11 +13,11 @@ namespace ScriptCs public class CompositionRoot { private readonly bool _debug; - private readonly string _logLevel; + private readonly LogLevel _logLevel; private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; - public CompositionRoot(bool debug, string logLevel) + public CompositionRoot(bool debug, LogLevel logLevel) { _debug = debug; _logLevel = logLevel; diff --git a/src/ScriptCs/LogLevel.cs b/src/ScriptCs/LogLevel.cs new file mode 100644 index 00000000..99a910b0 --- /dev/null +++ b/src/ScriptCs/LogLevel.cs @@ -0,0 +1,10 @@ +namespace ScriptCs +{ + public enum LogLevel + { + Error, + Info, + Debug, + Trace + } +} diff --git a/src/ScriptCs/LoggerConfigurator.cs b/src/ScriptCs/LoggerConfigurator.cs index 403e2db0..e3914031 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/src/ScriptCs/LoggerConfigurator.cs @@ -1,12 +1,11 @@ -using log4net; +using System.Globalization; +using log4net; using log4net.Appender; using log4net.Core; using log4net.Layout; using log4net.Repository.Hierarchy; - -using ICommonLog = Common.Logging.ILog; - using Common.Logging.Log4Net; +using ICommonLog = Common.Logging.ILog; namespace ScriptCs { @@ -15,11 +14,11 @@ public class LoggerConfigurator private const string Pattern = "%-5level Thread[%thread]: %message%newline"; private const string LoggerName = "scriptcs"; - private readonly string _logLevel; + private readonly LogLevel _logLevel; private ICommonLog _logger; - public LoggerConfigurator(string logLevel) + public LoggerConfigurator(LogLevel logLevel) { _logLevel = logLevel; } @@ -31,7 +30,7 @@ public void Configure() var consoleAppender = new ConsoleAppender { Layout = new PatternLayout(Pattern), - Threshold = hierarchy.LevelMap[_logLevel] + Threshold = hierarchy.LevelMap[_logLevel.ToString().ToUpper(CultureInfo.CurrentCulture)] }; hierarchy.Root.AddAppender(consoleAppender); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 929b951b..9b445864 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -65,6 +65,7 @@ + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index bfdfa2ec..8846c0d4 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -1,21 +1,14 @@ using System; using System.Linq; -using log4net; + using PowerArgs; using System.Globalization; -using log4net.Core; namespace ScriptCs { - - [ArgExample("scriptcs server.csx -debug", "Shows how to start the script with debug mode switched on")] public class ScriptCsArgs { - private const string ValidLogLevels = "error, info, debug, trace"; - - private string _logLevel; - [ArgDescription("Script file name, must be specified first")] [ArgPosition(0)] public string ScriptName { get; set; } @@ -24,20 +17,11 @@ public class ScriptCsArgs [ArgShortcut("debug")] public bool DebugFlag { get; set; } - [ArgDescription("Flag which defines the log level used. Possible values:" + ValidLogLevels)] + [ArgDescription("Flag which defines the log level used.")] [ArgShortcut("log")] - [DefaultValue("info")] - public string LogLevel - { - get - { - return _logLevel; - } - set - { - _logLevel = value.ToUpper(CultureInfo.CurrentUICulture); - } - } + [ArgIgnoreCase] + [DefaultValue(LogLevel.Info)] + public LogLevel LogLevel { get; set; } [ArgDescription("Installs and restores packages which are specified in packages.config")] [ArgShortcut("install")] @@ -61,27 +45,5 @@ public string LogLevel [ArgDescription("Outputs version information")] public bool Version { get; set; } - - - public bool IsValid() - { - return (!string.IsNullOrWhiteSpace(ScriptName) || Install != null) && this.IsLogLevelValid(); - } - - private bool IsLogLevelValid() - { - if (!ValidLogLevels.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Contains(LogLevel)) - { - return false; - } - - var repository = LogManager.GetRepository(); - var levelMap = repository.LevelMap; - return levelMap - .AllLevels - .Cast() - .Any(level => - level.Name.Equals(LogLevel, StringComparison.CurrentCulture)); - } } } \ No newline at end of file From 0c6430e565c64365136d2a6af7967b9af874bfb1 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 11 Apr 2013 10:22:23 +0200 Subject: [PATCH 0197/1224] Removed possible NullReferenceException on newestFramework --- src/ScriptCs.Core/Package/PackageContainer.cs | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index c90598fa..6954fbd7 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -34,7 +34,14 @@ public IEnumerable CreatePackageFile() var newestFramework = GetNewestSupportedFramework(package); packageReferenceFile.AddEntry(package.Id, package.Version, newestFramework); - yield return string.Format("{0}, Version {1}, .NET {2}", package.Id, package.Version, newestFramework.Version); + if (newestFramework == null) + { + yield return string.Format("{0}, Version {1}", package.Id, package.Version); + } + else + { + yield return string.Format("{0}, Version {1}, .NET {2}", package.Id, package.Version, newestFramework.Version); + } } } @@ -56,24 +63,38 @@ public IEnumerable FindReferences(string path) var references = packageReferenceFile.GetPackageReferences().ToList(); if (references.Any()) { - return references.Select(i => new PackageReference(i.Id, i.TargetFramework, i.Version.Version, i.Version.SpecialVersion)); + foreach (var packageReference in references) + { + yield return new PackageReference( + packageReference.Id, + packageReference.TargetFramework, + packageReference.Version.Version, + packageReference.Version.SpecialVersion); + } + + yield break; } // No packages.config, check packages folder var packagesFolder = Path.Combine(_fileSystem.GetWorkingDirectory(path), Constants.PackagesFolder); - if (_fileSystem.DirectoryExists(packagesFolder)) - { - var repository = new LocalPackageRepository(packagesFolder); + if (!_fileSystem.DirectoryExists(packagesFolder)) yield break; - var arbitraryPackages = repository.GetPackages(); - if (arbitraryPackages.Any()) - { - return arbitraryPackages.Select(i => - new PackageReference(i.Id, GetNewestSupportedFramework(i), i.Version.Version, i.Version.SpecialVersion)); - } - } + var repository = new LocalPackageRepository(packagesFolder); - return Enumerable.Empty(); + var arbitraryPackages = repository.GetPackages(); + if (!arbitraryPackages.Any()) yield break; + + foreach (var arbitraryPackage in arbitraryPackages) + { + var newestFramework = GetNewestSupportedFramework(arbitraryPackage) + ?? VersionUtility.EmptyFramework; + + yield return new PackageReference( + arbitraryPackage.Id, + newestFramework, + arbitraryPackage.Version.Version, + arbitraryPackage.Version.SpecialVersion); + } } private static FrameworkName GetNewestSupportedFramework(IPackage packageMetadata) From 2c1a2ec4c8f8edb1c04505764e9304db0aede929 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 11 Apr 2013 14:37:27 +0200 Subject: [PATCH 0198/1224] Added save command to -clean and -install (if no packages.config) --- src/ScriptCs/Command/CommandFactory.cs | 17 ++++++++- test/ScriptCs.Tests/CommandFactoryTests.cs | 43 ++++++++++++++++++---- test/ScriptCs.Tests/InstallCommandTests.cs | 10 ++++- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 9fb621e0..0fbb618f 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -1,4 +1,6 @@ -namespace ScriptCs.Command +using System.IO; + +namespace ScriptCs.Command { public class CommandFactory { @@ -46,17 +48,28 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver); + var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; + var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); + + if (!_scriptServiceRoot.FileSystem.FileExists(packageFile)) + { + var saveCommand = new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + return new CompositeCommand(installCommand, restoreCommand, saveCommand); + } + return new CompositeCommand(installCommand, restoreCommand); } if (args.Clean) { + var saveCommand = new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + var cleanCommand = new CleanCommand( args.ScriptName, _scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver); - return cleanCommand; + return new CompositeCommand(saveCommand, cleanCommand); } if (args.Save) diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index f0ee8d27..b8f1bdc1 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -10,20 +10,25 @@ public class CommandFactoryTests { public class CreateCommandMethod { - private static ScriptServiceRoot CreateRoot() + private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) { + const string CurrentDirectory = "C:\\"; + const string PackagesFile = "C:\\packages.config"; + var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fs.Setup(x => x.FileExists(PackagesFile)).Returns(packagesFileExists); + var resolver = new Mock(); var executor = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); - return root; + return new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object); } [Fact] - public void ShouldInstallWhenInstallFlagIsOn() + public void ShouldInstallAndRestoreWhenInstallFlagIsOn() { var args = new ScriptCsArgs { @@ -42,6 +47,27 @@ public void ShouldInstallWhenInstallFlagIsOn() (compositeCommand.Commands[1] is IRestoreCommand).ShouldBeTrue(); } + [Fact] + public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExists() + { + var args = new ScriptCsArgs + { + AllowPreReleaseFlag = false, + Install = "", + ScriptName = null + }; + + var factory = new CommandFactory(CreateRoot(packagesFileExists: false)); + var result = factory.CreateCommand(args); + + var compositeCommand = result as ICompositeCommand; + compositeCommand.ShouldNotBeNull(); + + (compositeCommand.Commands[0] is IInstallCommand).ShouldBeTrue(); + (compositeCommand.Commands[1] is IRestoreCommand).ShouldBeTrue(); + (compositeCommand.Commands[2] is ISaveCommand).ShouldBeTrue(); + } + [Fact] public void ShouldExecuteWhenScriptNameIsPassed() { @@ -90,15 +116,18 @@ public void ShouldRestoreWhenBothNameAndRestoreArePassed() } [Fact] - public void ShouldCleanWhenCleanFlagIsPassed() + public void ShouldSaveAndCleanWhenCleanFlagIsPassed() { var args = new ScriptCsArgs { Clean = true, ScriptName = null }; var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args); - result.ShouldNotBeNull(); - result.ShouldImplement(); + var compositeCommand = result as ICompositeCommand; + compositeCommand.ShouldNotBeNull(); + + (compositeCommand.Commands[0] is ISaveCommand).ShouldBeTrue(); + (compositeCommand.Commands[1] is ICleanCommand).ShouldBeTrue(); } [Fact] diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 6014c127..39369331 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -23,8 +23,11 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() ScriptName = null }; + const string CurrentDirectory = @"C:\"; + var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(@"C:\"); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); var resolver = new Mock(); var executor = new Mock(); @@ -50,8 +53,11 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() ScriptName = null }; + const string CurrentDirectory = @"C:\"; + var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(@"C:\"); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); var resolver = new Mock(); var executor = new Mock(); From c35a549620423447cc1dd53aa48e6a7be1a3394a Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 11 Apr 2013 15:50:52 +0200 Subject: [PATCH 0199/1224] Added assertions on Commands.Count for CompositeCommands, changed to ShouldImplement instead of casting --- test/ScriptCs.Tests/CommandFactoryTests.cs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index b8f1bdc1..956e6c86 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -43,8 +43,9 @@ public void ShouldInstallAndRestoreWhenInstallFlagIsOn() var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - (compositeCommand.Commands[0] is IInstallCommand).ShouldBeTrue(); - (compositeCommand.Commands[1] is IRestoreCommand).ShouldBeTrue(); + compositeCommand.Commands.Count.ShouldEqual(2); + compositeCommand.Commands[0].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); } [Fact] @@ -63,9 +64,10 @@ public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExist var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - (compositeCommand.Commands[0] is IInstallCommand).ShouldBeTrue(); - (compositeCommand.Commands[1] is IRestoreCommand).ShouldBeTrue(); - (compositeCommand.Commands[2] is ISaveCommand).ShouldBeTrue(); + compositeCommand.Commands.Count.ShouldEqual(3); + compositeCommand.Commands[0].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); + compositeCommand.Commands[2].ShouldImplement(); } [Fact] @@ -111,8 +113,9 @@ public void ShouldRestoreWhenBothNameAndRestoreArePassed() var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - (compositeCommand.Commands[0] is IRestoreCommand).ShouldBeTrue(); - (compositeCommand.Commands[1] is IScriptCommand).ShouldBeTrue(); + compositeCommand.Commands.Count.ShouldEqual(2); + compositeCommand.Commands[0].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); } [Fact] @@ -126,8 +129,9 @@ public void ShouldSaveAndCleanWhenCleanFlagIsPassed() var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - (compositeCommand.Commands[0] is ISaveCommand).ShouldBeTrue(); - (compositeCommand.Commands[1] is ICleanCommand).ShouldBeTrue(); + compositeCommand.Commands.Count.ShouldEqual(2); + compositeCommand.Commands[0].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); } [Fact] From 56d17b8581276a40c75c23e4cee5f3651339594e Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Fri, 12 Apr 2013 12:47:55 +0300 Subject: [PATCH 0200/1224] Fixes #201. PowerArgs updated to 1.5.0.0 --- src/ScriptCs/ScriptCs.csproj | 4 ++-- src/ScriptCs/packages.config | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 48e483c7..34d3e5f4 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -23,9 +23,9 @@ ..\..\packages\Autofac.Mef.3.0.1\lib\net40\Autofac.Integration.Mef.dll - + False - ..\..\packages\PowerArgs.1.4.1.0\lib\net40\PowerArgs.dll + ..\..\packages\PowerArgs.1.5.0.0\lib\net40\PowerArgs.dll diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index 737b4e92..d033ef13 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file From 4f3847d436d4abcef04d3652fffa2041fe189a3d Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 16 Apr 2013 20:53:21 -0400 Subject: [PATCH 0201/1224] Bundle all dependencies, except Roslyn, in the scriptcs chocolatey package --- src/ScriptCs/Properties/chocolateyInstall.ps1 | 5 +---- src/ScriptCs/Properties/scriptcs.nuspec | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ScriptCs/Properties/chocolateyInstall.ps1 b/src/ScriptCs/Properties/chocolateyInstall.ps1 index f4ca4243..68598df8 100644 --- a/src/ScriptCs/Properties/chocolateyInstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyInstall.ps1 @@ -11,13 +11,10 @@ Write-Host "Retrieving NuGet dependencies..." -ForegroundColor DarkYellow $dependencies = @{ - "NuGet.Core" = "2.2.0"; - "Autofac.Mef" = "3.0.0"; "Roslyn.Compilers.CSharp" = "1.2.20906.2"; - "PowerArgs" = "1.4.1.0"; } - $dependencies.GetEnumerator() | %{ .$nuget install $_.Name -version $_.Value -o $nugetPath -nocache } | Out-Null + $dependencies.GetEnumerator() | %{ .$nuget install $_.Name -version $_.Value -o $nugetPath } Get-ChildItem $nugetPath -Filter "*.dll" -Recurse | %{ Copy-Item $_.FullName $binPath -Force } Remove-Item $nugetPath -Recurse -Force diff --git a/src/ScriptCs/Properties/scriptcs.nuspec b/src/ScriptCs/Properties/scriptcs.nuspec index 1adaf7ce..813821b9 100644 --- a/src/ScriptCs/Properties/scriptcs.nuspec +++ b/src/ScriptCs/Properties/scriptcs.nuspec @@ -18,7 +18,7 @@ - - + + \ No newline at end of file From 8d5de12a38ef227244604b0042ae3293c27f7b3b Mon Sep 17 00:00:00 2001 From: Denis Mentey Date: Thu, 25 Apr 2013 00:31:37 +0300 Subject: [PATCH 0202/1224] Fixes #209. Double package installation success message fixed. --- src/ScriptCs/Command/InstallCommand.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index d88ca79d..84761252 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -43,7 +43,6 @@ public CommandResult Execute() { _packageInstaller.InstallPackages(packages, _allowPre, Console.WriteLine); - Console.WriteLine("Installation completed successfully."); return CommandResult.Success; } catch (Exception e) From 4b496864923fb5afc24c1b5aeb825c37eb035972 Mon Sep 17 00:00:00 2001 From: dschenkelman Date: Sun, 28 Apr 2013 21:36:36 -0300 Subject: [PATCH 0203/1224] # Updated LoggerConfigurator.cs to display thread only for debug and trace levels --- src/ScriptCs/LoggerConfigurator.cs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs/LoggerConfigurator.cs b/src/ScriptCs/LoggerConfigurator.cs index e3914031..c49399b3 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/src/ScriptCs/LoggerConfigurator.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System; +using System.Globalization; using log4net; using log4net.Appender; using log4net.Core; @@ -11,7 +12,8 @@ namespace ScriptCs { public class LoggerConfigurator { - private const string Pattern = "%-5level Thread[%thread]: %message%newline"; + private const string ThreadPattern = " Thread[%thread]"; + private const string Pattern = "%-5level{threadLevel}: %message%newline"; private const string LoggerName = "scriptcs"; private readonly LogLevel _logLevel; @@ -29,7 +31,7 @@ public void Configure() var logger = LogManager.GetLogger(LoggerName); var consoleAppender = new ConsoleAppender { - Layout = new PatternLayout(Pattern), + Layout = new PatternLayout(GetLogPattern(_logLevel)), Threshold = hierarchy.LevelMap[_logLevel.ToString().ToUpper(CultureInfo.CurrentCulture)] }; @@ -45,6 +47,21 @@ public ICommonLog GetLogger() return _logger; } + private static string GetLogPattern(LogLevel logLevel) + { + switch (logLevel) + { + case LogLevel.Error: + case LogLevel.Info: + return Pattern.Replace("{threadLevel}", string.Empty); + case LogLevel.Debug: + case LogLevel.Trace: + return Pattern.Replace("{threadLevel}", ThreadPattern); + default: + throw new ArgumentOutOfRangeException("logLevel"); + } + } + private class CodeConfigurableLog4NetLogger : Log4NetLogger { protected internal CodeConfigurableLog4NetLogger(ILoggerWrapper log) From 778eed9574edf3619faee9a8688473213ec3aafd Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sun, 5 May 2013 22:28:45 -0700 Subject: [PATCH 0204/1224] adding state to the ScriptPackSession in order to store the Roslyn Session to enable the REPL --- src/ScriptCs.Core/ScriptPackSession.cs | 10 ++- .../RoslynScriptEngine.cs | 17 ++++- .../ScriptPackSessionTests.cs | 5 ++ .../RoslynScriptEngineTests.cs | 63 +++++++++++++++++-- 4 files changed, 86 insertions(+), 9 deletions(-) diff --git a/src/ScriptCs.Core/ScriptPackSession.cs b/src/ScriptCs.Core/ScriptPackSession.cs index 52046bf9..30d4a07b 100644 --- a/src/ScriptCs.Core/ScriptPackSession.cs +++ b/src/ScriptCs.Core/ScriptPackSession.cs @@ -8,7 +8,8 @@ namespace ScriptCs public class ScriptPackSession : IScriptPackSession { private readonly IEnumerable _scriptPacks; - private readonly IEnumerable _contexts; + private readonly IEnumerable _contexts; + private readonly IDictionary _state; private IList _references; private IList _namespaces; @@ -19,7 +20,7 @@ public ScriptPackSession(IEnumerable scriptPacks) _contexts = _scriptPacks.Select(s => s.GetContext()).Where(c=>c != null); _references = new List(); _namespaces = new List(); - + _state = new Dictionary(); AddScriptContextNamespace(); } @@ -62,6 +63,11 @@ public void TerminatePacks() } } + public IDictionary State + { + get { return _state; } + } + void IScriptPackSession.AddReference(string assemblyDisplayNameOrPath) { _references.Add(assemblyDisplayNameOrPath); diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 1de6c02a..cc024ba2 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -12,6 +12,7 @@ public class RoslynScriptEngine : IScriptEngine private readonly ScriptEngine _scriptEngine; private readonly IScriptHostFactory _scriptHostFactory; private readonly ILog _logger; + public const string SessionKey = "Session"; public RoslynScriptEngine(IScriptHostFactory scriptHostFactory, ILog logger) { @@ -20,7 +21,7 @@ public RoslynScriptEngine(IScriptHostFactory scriptHostFactory, ILog logger) _scriptHostFactory = scriptHostFactory; _logger = logger; } - + public string BaseDirectory { get { return _scriptEngine.BaseDirectory; } @@ -32,8 +33,18 @@ public void Execute(string code, IEnumerable references, IEnumerable scriptHostFactory = null) { @@ -19,15 +38,20 @@ private static RoslynScriptEngine CreateScriptEngine( return new RoslynScriptEngine(scriptHostFactory.Object, logger.Object); } + private static TestRoslynScriptEngine CreateTestScriptEngine( + Mock scriptHostFactory = null) + { + scriptHostFactory = scriptHostFactory ?? new Mock(); + var logger = new Mock(); + + return new TestRoslynScriptEngine(scriptHostFactory.Object, logger.Object); + } + public class TheExecuteMethod { [Fact] public void ShouldCreateScriptHostWithContexts() { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var scriptHostFactory = new Mock(); scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); @@ -45,6 +69,37 @@ public void ShouldCreateScriptHostWithContexts() scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny())); } + + [Fact] + public void ShouldReuseExistingSessionIfProvided() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + + var code = "var a = 0;"; + + var engine = CreateTestScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = roslynEngine.CreateSession(); + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); + engine.Session.ShouldEqual(session); + } + + [Fact] + public void ShouldCreateNewSessionIfNotProvided() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + + var code = "var a = 0;"; + + var engine = CreateTestScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); + engine.Session.ShouldNotBeNull(); + } } } } \ No newline at end of file From 3469c43536dda12e9fdf29bd653e0618fcabd350 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sun, 5 May 2013 23:00:01 -0700 Subject: [PATCH 0205/1224] Adding -help / -? for returning help --- src/ScriptCs/Command/CommandFactory.cs | 5 +++++ src/ScriptCs/Command/HelpCommand.cs | 26 ++++++++++++++++++++++ src/ScriptCs/Command/ICommand.cs | 2 ++ src/ScriptCs/ScriptCs.csproj | 1 + src/ScriptCs/ScriptCsArgs.cs | 6 +++++ test/ScriptCs.Tests/CommandFactoryTests.cs | 14 ++++++++++++ 6 files changed, 54 insertions(+) create mode 100644 src/ScriptCs/Command/HelpCommand.cs diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 7621a7f5..32c87889 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -13,6 +13,11 @@ public CommandFactory(ScriptServiceRoot scriptServiceRoot) public ICommand CreateCommand(ScriptCsArgs args) { + if (args.Help) + { + return new HelpCommand(_scriptServiceRoot.Logger); + } + if (args.ScriptName != null) { var executeCommand = new ExecuteScriptCommand( diff --git a/src/ScriptCs/Command/HelpCommand.cs b/src/ScriptCs/Command/HelpCommand.cs new file mode 100644 index 00000000..f37b06f1 --- /dev/null +++ b/src/ScriptCs/Command/HelpCommand.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Common.Logging; +using PowerArgs; + +namespace ScriptCs.Command +{ + internal class HelpCommand : IHelpCommand + { + private readonly ILog _logger; + + public HelpCommand(ILog logger) + { + _logger = logger; + } + + public CommandResult Execute() + { + _logger.Info(ArgUsage.GetUsage()); + return CommandResult.Success; + } + } +} diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index 1f171578..ec1477b9 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -14,6 +14,8 @@ public interface IInstallCommand : ICommand { } public interface IInvalidCommand : ICommand { } + public interface IHelpCommand : ICommand { } + public interface ICompositeCommand : ICommand { List Commands { get; } diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index ba8cec88..74ed25fc 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -58,6 +58,7 @@ + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 8846c0d4..9c6b99c4 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -13,6 +13,12 @@ public class ScriptCsArgs [ArgPosition(0)] public string ScriptName { get; set; } + [ArgDescription("Displays help")] + + [ArgShortcut("?")] + public bool Help { get; set; } + + [ArgDescription("Flag which switches on debug mode")] [ArgShortcut("debug")] public bool DebugFlag { get; set; } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 016f1bd0..e56c8550 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -164,6 +164,20 @@ public void ShouldReturnInvalidWhenNoNameOrInstallSet() result.ShouldImplement(); } + + [Fact] + public void ShouldReturnHelpCommandWhenHelpIsPassed() + { + var args = new ScriptCsArgs + { + Help = true + }; + + var factory = new CommandFactory(CreateRoot()); + var result = factory.CreateCommand(args); + + result.ShouldImplement(); + } } } } From 32a23bc410ecb44dbcd598484be7fb13aad11399 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 6 May 2013 01:07:53 -0700 Subject: [PATCH 0206/1224] Adding repl support --- src/ScriptCs.Core/ScriptExecutor.cs | 2 +- .../RoslynScriptEngine.cs | 30 +++---- src/ScriptCs/Command/CommandFactory.cs | 9 ++ src/ScriptCs/Command/ExecuteReplCommand.cs | 82 +++++++++++++++++++ src/ScriptCs/Program.cs | 43 ++++++---- src/ScriptCs/ScriptCs.csproj | 2 + src/ScriptCs/ScriptCsArgs.cs | 3 + 7 files changed, 139 insertions(+), 32 deletions(-) create mode 100644 src/ScriptCs/Command/ExecuteReplCommand.cs diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index d809998b..c4a15e4d 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -15,7 +15,7 @@ public class ScriptExecutor : IScriptExecutor private readonly IFilePreProcessor _filePreProcessor; private readonly IScriptEngine _scriptEngine; private readonly ILog _logger; - + public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) { _fileSystem = fileSystem; diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index cc024ba2..ddafd230 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -32,13 +32,27 @@ public void Execute(string code, IEnumerable references, IEnumerable references, IEnumerable GetAssemblyPaths(string workingDirectory) + { + var binFolder = Path.Combine(workingDirectory, "bin"); + + if (!_fileSystem.DirectoryExists(binFolder)) + _fileSystem.CreateDirectory(binFolder); + + var assemblyPaths = + _fileSystem.EnumerateFiles(binFolder, "*.dll") + .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) + .ToList(); + + foreach (var path in assemblyPaths.Select(Path.GetFileName)) + { + _logger.DebugFormat("Found assembly reference: {0}", path); + } + + return assemblyPaths; + } + } +} diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 0d3d0f55..f04a7d58 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -11,41 +11,50 @@ internal class Program private static int Main(string[] args) { ILog logger = null; - ScriptCsArgs commandArgs; - + ScriptCsArgs commandArgs = null; + const string unexpectedArgumentMessage = "Unexpected Argument: "; - - try + + if (args.Length > 0) { - commandArgs = Args.Parse(args); - } - catch (ArgException ex) - { - commandArgs = new ScriptCsArgs(); - - if (ex.Message.StartsWith(unexpectedArgumentMessage)) + try { - var token = ex.Message.Substring(unexpectedArgumentMessage.Length); - Console.WriteLine("Parameter \"{0}\" is not supported!", token); + commandArgs = Args.Parse(args); } - else + catch (ArgException ex) { - Console.WriteLine(ex.Message); + commandArgs = new ScriptCsArgs(); + + if (ex.Message.StartsWith(unexpectedArgumentMessage)) + { + var token = ex.Message.Substring(unexpectedArgumentMessage.Length); + Console.WriteLine("Parameter \"{0}\" is not supported!", token); + } + else + { + Console.WriteLine(ex.Message); + } } } + if (commandArgs == null) + { + commandArgs = new ScriptCsArgs() {Repl = true}; + } + var debug = commandArgs.DebugFlag; var logLevel = commandArgs.LogLevel; - var scriptProvided = !string.IsNullOrWhiteSpace(commandArgs.ScriptName); + var scriptProvided = !string.IsNullOrWhiteSpace(commandArgs.ScriptName) || commandArgs.Repl; + var compositionRoot = new CompositionRoot(debug, scriptProvided, logLevel); compositionRoot.Initialize(); logger = compositionRoot.GetLogger(); logger.Debug("Creating ScriptServiceRoot"); + var scriptServiceRoot = compositionRoot.GetServiceRoot(); var commandFactory = new CommandFactory(scriptServiceRoot); var command = commandFactory.CreateCommand(commandArgs); - var result = command.Execute(); switch (result) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 74ed25fc..ac20f17e 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -58,6 +58,7 @@ + @@ -69,6 +70,7 @@ + diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 9c6b99c4..cf120358 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -9,6 +9,9 @@ namespace ScriptCs [ArgExample("scriptcs server.csx -debug", "Shows how to start the script with debug mode switched on")] public class ScriptCsArgs { + [ArgIgnore] + public bool Repl { get; set; } + [ArgDescription("Script file name, must be specified first")] [ArgPosition(0)] public string ScriptName { get; set; } From 2a462db1f2b7e969f964ad342a2f891439c59ca5 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 6 May 2013 01:17:42 -0700 Subject: [PATCH 0207/1224] Adding missing file --- src/ScriptCs/Repl.cs | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/ScriptCs/Repl.cs diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs new file mode 100644 index 00000000..ac65b154 --- /dev/null +++ b/src/ScriptCs/Repl.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Common.Logging; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public class Repl + { + private static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; + + private readonly IFileSystem _fileSystem; + private readonly IScriptEngine _scriptEngine; + private readonly ILog _logger; + private ScriptPackSession _scriptPackSession; + private IEnumerable _references; + + public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger) + { + _fileSystem = fileSystem; + _scriptEngine = scriptEngine; + _logger = logger; + } + + public void Initialize(IEnumerable paths, IEnumerable scriptPacks) + { + _references = DefaultReferences.Union(paths); + var bin = Path.Combine(_fileSystem.CurrentDirectory, "bin"); + + _scriptEngine.BaseDirectory = bin; + + _logger.Debug("Initializing script packs"); + var scriptPackSession = new ScriptPackSession(scriptPacks); + + scriptPackSession.InitializePacks(); + _scriptPackSession = scriptPackSession; + + } + + public void Terminate() + { + _logger.Debug("Terminating packs"); + _scriptPackSession.TerminatePacks(); + } + + public void Execute(string script) + { + _scriptEngine.Execute(script, _references, DefaultNamespaces, _scriptPackSession); + } + } +} From d936c2461a5be78241c39537a755b5a736cf9543 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 6 May 2013 16:31:06 -0700 Subject: [PATCH 0208/1224] Adding exception handling. Display the error and don't exit --- src/ScriptCs/Repl.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index ac65b154..8f8f8811 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -50,7 +50,14 @@ public void Terminate() public void Execute(string script) { - _scriptEngine.Execute(script, _references, DefaultNamespaces, _scriptPackSession); + try + { + _scriptEngine.Execute(script, _references, DefaultNamespaces, _scriptPackSession); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } } } } From 4d2f7f7eabb450134cc34ba0a6f1e2b4dd8a2100 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 6 May 2013 17:49:25 -0700 Subject: [PATCH 0209/1224] make errors red --- src/ScriptCs/Repl.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 8f8f8811..974fd374 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -56,7 +56,10 @@ public void Execute(string script) } catch (Exception ex) { + var foregroundColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(ex); + Console.ForegroundColor = foregroundColor; } } } From d74169dca895d2238ee0105a4227f1769d9f8c0c Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 6 May 2013 18:04:25 -0700 Subject: [PATCH 0210/1224] adding colors for output --- src/ScriptCs/Repl.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 974fd374..0ad6c5d7 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -50,17 +50,20 @@ public void Terminate() public void Execute(string script) { + var foregroundColor = Console.ForegroundColor; + try { + Console.ForegroundColor = ConsoleColor.Cyan; _scriptEngine.Execute(script, _references, DefaultNamespaces, _scriptPackSession); } catch (Exception ex) { - var foregroundColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(ex); - Console.ForegroundColor = foregroundColor; } + Console.ForegroundColor = foregroundColor; + } } } From 826db44ca4960ea94d5b926c2524c286e3d4b1e1 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 6 May 2013 21:42:59 -0700 Subject: [PATCH 0211/1224] Adding '>' prefix and blank lines --- src/ScriptCs/Command/ExecuteReplCommand.cs | 1 + src/ScriptCs/Repl.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 880e3473..d8c8534c 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -50,6 +50,7 @@ public CommandResult Execute() private bool ExecuteLine(Repl repl) { + Console.Write("> "); var line = Console.ReadLine(); if (line == "") return false; diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 0ad6c5d7..f71d5206 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -60,7 +60,7 @@ public void Execute(string script) catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(ex); + Console.WriteLine("\r\n" + ex + "\r\n"); } Console.ForegroundColor = foregroundColor; From 892862074442e8eb1036ccba6e453a420b84df75 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 7 May 2013 00:11:45 -0700 Subject: [PATCH 0212/1224] added engine to service root, refactored ReplCommand to grab engine off the root --- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/ScriptServiceRoot.cs | 5 ++++- test/ScriptCs.Tests/CleanCommandTests.cs | 12 ++++++++---- test/ScriptCs.Tests/CommandFactoryTests.cs | 3 ++- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 6 ++++-- test/ScriptCs.Tests/InstallCommandTests.cs | 6 ++++-- test/ScriptCs.Tests/RestoreCommandTests.cs | 9 ++++++--- test/ScriptCs.Tests/VersionCommandTests.cs | 3 ++- 8 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 9516ef97..ed68acb5 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -23,7 +23,7 @@ public ICommand CreateCommand(ScriptCsArgs args) { var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - new RoslynScriptEngine(new ScriptHostFactory(), _scriptServiceRoot.Logger), _scriptServiceRoot.Logger); + _scriptServiceRoot.Engine, _scriptServiceRoot.Logger); return replCommand; } diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index c11f3afd..2f9e0f93 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -8,7 +8,8 @@ public class ScriptServiceRoot public ScriptServiceRoot( IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, - IScriptExecutor executor, + IScriptExecutor executor, + IScriptEngine engine, IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger) @@ -16,6 +17,7 @@ public ScriptServiceRoot( FileSystem = fileSystem; PackageAssemblyResolver = packageAssemblyResolver; Executor = executor; + Engine = engine; ScriptPackResolver = scriptPackResolver; PackageInstaller = packageInstaller; Logger = logger; @@ -27,5 +29,6 @@ public ScriptServiceRoot( public IScriptPackResolver ScriptPackResolver { get; private set; } public IPackageInstaller PackageInstaller { get; private set; } public ILog Logger { get; private set; } + public IScriptEngine Engine { get; private set; } } } \ No newline at end of file diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 4b627501..8e8bf61c 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -19,10 +19,11 @@ public void ShouldDeletePackagesFolder() var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -43,10 +44,11 @@ public void ShouldDeleteBinFolder() var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -67,10 +69,11 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -92,10 +95,11 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index e56c8550..8c43816b 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -22,10 +22,11 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 58feec14..33ea21f7 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -26,10 +26,11 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -54,10 +55,11 @@ public void ShouldCreateMissingBinFolder() var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index f6ae0a2b..4c842058 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -32,10 +32,11 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -63,10 +64,11 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index eb9d4388..e1b53ffd 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -20,10 +20,11 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); const string CurrentDirectory = @"C:\"; @@ -58,10 +59,11 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); const string CurrentDirectory = @"C:\"; @@ -96,10 +98,11 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index f321d96a..d5e6ccfa 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -37,10 +37,11 @@ public void VersionCommandShouldOutputVersion() var fs = new Mock(); var resolver = new Mock(); var executor = new Mock(); + var engine = new Mock(); var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); From 5c018cc18feaa54d5fbb28582d2c2bebc630e09c Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 7 May 2013 00:32:04 -0700 Subject: [PATCH 0213/1224] Adding console wrappers and refactoring Repl to use --- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 +++++-- src/ScriptCs/CompositionRoot.cs | 3 ++- src/ScriptCs/IConsole.cs | 18 ++++++++++++++ src/ScriptCs/Repl.cs | 15 ++++++------ src/ScriptCs/ReplConsole.cs | 28 ++++++++++++++++++++++ src/ScriptCs/ScriptCs.csproj | 2 ++ src/ScriptCs/ScriptServiceRoot.cs | 5 +++- 8 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 src/ScriptCs/IConsole.cs create mode 100644 src/ScriptCs/ReplConsole.cs diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index ed68acb5..bb9a1452 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -23,7 +23,7 @@ public ICommand CreateCommand(ScriptCsArgs args) { var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Engine, _scriptServiceRoot.Logger); + _scriptServiceRoot.Engine, _scriptServiceRoot.Logger, _scriptServiceRoot.Console); return replCommand; } diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index d8c8534c..8ce85c9e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,23 +15,27 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptEngine _scriptEngine; private readonly ILog _logger; + private readonly IConsole _console; public ExecuteReplCommand( IFileSystem fileSystem, IScriptPackResolver scriptPackResolver, IScriptEngine scriptEngine, - ILog logger) + ILog logger, + IConsole console + ) { _fileSystem = fileSystem; _scriptPackResolver = scriptPackResolver; _scriptEngine = scriptEngine; _logger = logger; + _console = console; } public CommandResult Execute() { Console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); - var repl = new Repl(_fileSystem, _scriptEngine, _logger); + var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console); repl.Initialize(GetAssemblyPaths(_fileSystem.CurrentDirectory), _scriptPackResolver.GetPacks()); try { diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 825e6164..086091da 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -44,7 +44,8 @@ public void Initialize() typeof (FilePreProcessor), typeof (ScriptPackResolver), typeof (NugetInstallationProvider), - typeof (PackageInstaller) + typeof (PackageInstaller), + typeof (ReplConsole) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/src/ScriptCs/IConsole.cs b/src/ScriptCs/IConsole.cs new file mode 100644 index 00000000..cde0a8b5 --- /dev/null +++ b/src/ScriptCs/IConsole.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs +{ + public interface IConsole + { + void Write(string value); + void WriteLine(string value); + string ReadLine(); + ConsoleColor ForegroundColor { get; set; } + } +} + + diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index f71d5206..2b289711 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -17,14 +17,16 @@ public class Repl private readonly IFileSystem _fileSystem; private readonly IScriptEngine _scriptEngine; private readonly ILog _logger; + private readonly IConsole _console; private ScriptPackSession _scriptPackSession; private IEnumerable _references; - public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger) + public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console) { _fileSystem = fileSystem; _scriptEngine = scriptEngine; _logger = logger; + _console = console; } public void Initialize(IEnumerable paths, IEnumerable scriptPacks) @@ -50,20 +52,19 @@ public void Terminate() public void Execute(string script) { - var foregroundColor = Console.ForegroundColor; + var foregroundColor = _console.ForegroundColor; try { - Console.ForegroundColor = ConsoleColor.Cyan; + _console.ForegroundColor = ConsoleColor.Cyan; _scriptEngine.Execute(script, _references, DefaultNamespaces, _scriptPackSession); } catch (Exception ex) { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("\r\n" + ex + "\r\n"); + _console.ForegroundColor = ConsoleColor.Red; + _console.WriteLine("\r\n" + ex + "\r\n"); } - Console.ForegroundColor = foregroundColor; - + _console.ForegroundColor = foregroundColor; } } } diff --git a/src/ScriptCs/ReplConsole.cs b/src/ScriptCs/ReplConsole.cs new file mode 100644 index 00000000..6100ce2b --- /dev/null +++ b/src/ScriptCs/ReplConsole.cs @@ -0,0 +1,28 @@ +using System; + +namespace ScriptCs +{ + public class ReplConsole : IConsole + { + public void Write(string value) + { + Console.Write(value); + } + + public void WriteLine(string value) + { + Console.WriteLine(value); + } + + public string ReadLine() + { + return Console.ReadLine(); + } + + public ConsoleColor ForegroundColor + { + get { return Console.ForegroundColor; } + set { Console.ForegroundColor = value; } + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index ac20f17e..196453f6 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -68,9 +68,11 @@ + + diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index 2f9e0f93..2da8bdb6 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -12,7 +12,8 @@ public ScriptServiceRoot( IScriptEngine engine, IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, - ILog logger) + ILog logger, + IConsole console = null) { FileSystem = fileSystem; PackageAssemblyResolver = packageAssemblyResolver; @@ -21,6 +22,7 @@ public ScriptServiceRoot( ScriptPackResolver = scriptPackResolver; PackageInstaller = packageInstaller; Logger = logger; + Console = console; } public IFileSystem FileSystem { get; private set; } @@ -30,5 +32,6 @@ public ScriptServiceRoot( public IPackageInstaller PackageInstaller { get; private set; } public ILog Logger { get; private set; } public IScriptEngine Engine { get; private set; } + public IConsole Console { get; private set; } } } \ No newline at end of file From 2fa8a2b743d2814deb873161e5fd3f7e569d4d9a Mon Sep 17 00:00:00 2001 From: Filip W Date: Tue, 7 May 2013 22:36:57 -0400 Subject: [PATCH 0214/1224] moved out static pre processor stuff to a util class, as it will be used by REPL. Later we may want to do it by inheritance, but for now it's good enough --- src/ScriptCs.Core/FilePreProcessor.cs | 40 ++++++-------------------- src/ScriptCs.Core/PreProcessorUtil.cs | 35 ++++++++++++++++++++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + 3 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 src/ScriptCs.Core/PreProcessorUtil.cs diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index b1479b59..1a7763d2 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -6,10 +6,6 @@ namespace ScriptCs { public class FilePreProcessor : IFilePreProcessor { - private const string LoadString = "#load "; - private const string UsingString = "using "; - private const string RString = "#r "; - private readonly ILog _logger; protected readonly IFileSystem _fileSystem; @@ -63,9 +59,9 @@ protected virtual string GenerateRs(ICollection rLines) private string ParseFile(string path, IEnumerable file, ref List usings, ref List rs, ref List loads) { var fileList = file.ToList(); - var firstCode = fileList.FindIndex(l => IsNonDirectiveLine(l)); + var firstCode = fileList.FindIndex(l => PreProcessorUtil.IsNonDirectiveLine(l)); - var firstBody = fileList.FindIndex(l => IsNonDirectiveLine(l) && !IsUsingLine(l)); + var firstBody = fileList.FindIndex(l => PreProcessorUtil.IsNonDirectiveLine(l) && !PreProcessorUtil.IsUsingLine(l)); // add #line before the actual code begins // +1 because we are in a zero indexed list, but line numbers are 1 indexed @@ -79,11 +75,11 @@ private string ParseFile(string path, IEnumerable file, ref List for (var i = 0; i < fileList.Count; i++) { var line = fileList[i]; - if (IsUsingLine(line)) + if (PreProcessorUtil.IsUsingLine(line)) { usings.Add(line); - } - else if (IsRLine(line)) + } + else if (PreProcessorUtil.IsRLine(line)) { if (i < firstCode) { @@ -94,11 +90,11 @@ private string ParseFile(string path, IEnumerable file, ref List fileList[i] = string.Empty; } } - else if (IsLoadLine(line)) + else if (PreProcessorUtil.IsLoadLine(line)) { if ((i < firstCode || firstCode < 0) && !loads.Contains(line)) { - var filepath = line.Trim(' ').Replace(LoadString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); + var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); var filecontent = _fileSystem.IsPathRooted(filepath) ? _fileSystem.ReadFileLines(filepath) : _fileSystem.ReadFileLines(_fileSystem.CurrentDirectory + @"\" + filepath); @@ -118,28 +114,8 @@ private string ParseFile(string path, IEnumerable file, ref List } } - var result = string.Join(_fileSystem.NewLine, fileList.Where(line => !IsUsingLine(line) && !IsRLine(line))); + var result = string.Join(_fileSystem.NewLine, fileList.Where(line => !PreProcessorUtil.IsUsingLine(line) && !PreProcessorUtil.IsRLine(line))); return result; } - - private static bool IsNonDirectiveLine(string line) - { - return !IsRLine(line) && !IsLoadLine(line) && line.Trim() != string.Empty; - } - - private static bool IsUsingLine(string line) - { - return line.TrimStart(' ').StartsWith(UsingString) && !line.Contains("{") && line.Contains(";"); - } - - private static bool IsRLine(string line) - { - return line.TrimStart(' ').StartsWith(RString); - } - - private static bool IsLoadLine(string line) - { - return line.TrimStart(' ').StartsWith(LoadString); - } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/PreProcessorUtil.cs b/src/ScriptCs.Core/PreProcessorUtil.cs new file mode 100644 index 00000000..d9ad5016 --- /dev/null +++ b/src/ScriptCs.Core/PreProcessorUtil.cs @@ -0,0 +1,35 @@ +namespace ScriptCs +{ + public static class PreProcessorUtil + { + public const string LoadString = "#load "; + public const string UsingString = "using "; + public const string RString = "#r "; + + public static bool IsNonDirectiveLine(string line) + { + return !IsRLine(line) && !IsLoadLine(line) && line.Trim() != string.Empty; + } + + public static bool IsUsingLine(string line) + { + return line.TrimStart(' ').StartsWith(UsingString) && !line.Contains("{") && line.Contains(";"); + } + + public static bool IsRLine(string line) + { + return line.TrimStart(' ').StartsWith(RString); + } + + public static bool IsLoadLine(string line) + { + return line.TrimStart(' ').StartsWith(LoadString); + } + + public static string GetPath(string replaceString, string line) + { + var filepath = line.Trim(' ').Replace(replaceString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); + return filepath; + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 7b729a0d..48d287f0 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -69,6 +69,7 @@ + From f574ebe7f8dcb15d754cd9652cac4eca67c3b315 Mon Sep 17 00:00:00 2001 From: Filip W Date: Tue, 7 May 2013 22:39:45 -0400 Subject: [PATCH 0215/1224] added filepreprocessor to process #r and #load in REPL --- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/Command/ExecuteReplCommand.cs | 15 +++++++++++++++ src/ScriptCs/Repl.cs | 5 +++++ src/ScriptCs/ScriptServiceRoot.cs | 3 +++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index bb9a1452..f317f424 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -23,7 +23,7 @@ public ICommand CreateCommand(ScriptCsArgs args) { var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Engine, _scriptServiceRoot.Logger, _scriptServiceRoot.Console); + _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console); return replCommand; } diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 8ce85c9e..b05d91bd 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -13,6 +13,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; + private readonly IFilePreProcessor _filePreProcessor; private readonly ILog _logger; private readonly IConsole _console; @@ -21,6 +22,7 @@ public ExecuteReplCommand( IFileSystem fileSystem, IScriptPackResolver scriptPackResolver, IScriptEngine scriptEngine, + IFilePreProcessor filePreProcessor, ILog logger, IConsole console ) @@ -28,6 +30,7 @@ IConsole console _fileSystem = fileSystem; _scriptPackResolver = scriptPackResolver; _scriptEngine = scriptEngine; + _filePreProcessor = filePreProcessor; _logger = logger; _console = console; } @@ -59,6 +62,18 @@ private bool ExecuteLine(Repl repl) if (line == "") return false; + if (PreProcessorUtil.IsLoadLine(line)) + { + var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); + line = _filePreProcessor.ProcessFile(filepath); + } + else if (PreProcessorUtil.IsRLine(line)) + { + var assemblyPath = PreProcessorUtil.GetPath(PreProcessorUtil.RString, line); + repl.AddReference(assemblyPath); + return true; + } + repl.Execute(line); return true; } diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 2b289711..61ea788b 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -44,6 +44,11 @@ public void Initialize(IEnumerable paths, IEnumerable scrip } + public void AddReference(string assembly) + { + _references = _references.Union(new[] { assembly }); + } + public void Terminate() { _logger.Debug("Terminating packs"); diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index 2da8bdb6..40a83c99 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -10,6 +10,7 @@ public ScriptServiceRoot( IPackageAssemblyResolver packageAssemblyResolver, IScriptExecutor executor, IScriptEngine engine, + IFilePreProcessor filePreProcessor, IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, @@ -19,6 +20,7 @@ public ScriptServiceRoot( PackageAssemblyResolver = packageAssemblyResolver; Executor = executor; Engine = engine; + FilePreProcessor = filePreProcessor; ScriptPackResolver = scriptPackResolver; PackageInstaller = packageInstaller; Logger = logger; @@ -32,6 +34,7 @@ public ScriptServiceRoot( public IPackageInstaller PackageInstaller { get; private set; } public ILog Logger { get; private set; } public IScriptEngine Engine { get; private set; } + public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } } } \ No newline at end of file From c47907f59c9c853dac50fe3bd742b1acf93ec5f0 Mon Sep 17 00:00:00 2001 From: Filip W Date: Tue, 7 May 2013 22:46:36 -0400 Subject: [PATCH 0216/1224] fixed tests that wouldn't compile --- test/ScriptCs.Tests/CleanCommandTests.cs | 12 ++++++++---- test/ScriptCs.Tests/CommandFactoryTests.cs | 3 ++- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 6 ++++-- test/ScriptCs.Tests/InstallCommandTests.cs | 6 ++++-- test/ScriptCs.Tests/RestoreCommandTests.cs | 9 ++++++--- test/ScriptCs.Tests/VersionCommandTests.cs | 3 ++- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 8e8bf61c..55e4b4ce 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -23,7 +23,8 @@ public void ShouldDeletePackagesFolder() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -48,7 +49,8 @@ public void ShouldDeleteBinFolder() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -73,7 +75,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -99,7 +102,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 8c43816b..125ec1d2 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -26,7 +26,8 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 33ea21f7..4b930ef1 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -30,7 +30,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -59,7 +60,8 @@ public void ShouldCreateMissingBinFolder() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 4c842058..5aeeb560 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -36,7 +36,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -68,7 +69,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index e1b53ffd..947f11e7 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -24,7 +24,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); const string CurrentDirectory = @"C:\"; @@ -63,7 +64,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); const string CurrentDirectory = @"C:\"; @@ -102,7 +104,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index d5e6ccfa..29fb50e1 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -41,7 +41,8 @@ public void VersionCommandShouldOutputVersion() var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); var logger = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var filePreProcessor = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); From f4708b1802c041847cd8e0dc5e376c5b070bb1e9 Mon Sep 17 00:00:00 2001 From: Filip W Date: Tue, 7 May 2013 22:49:30 -0400 Subject: [PATCH 0217/1224] added support for adding references during REPL runtime --- .../RoslynScriptEngine.cs | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ddafd230..e2947216 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -32,16 +32,17 @@ public void Execute(string code, IEnumerable references, IEnumerable references, IEnumerable References { get; set; } + } } } \ No newline at end of file From 74729e428094f7390f43ee998aa7a599d51e85e5 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 7 May 2013 22:38:16 -0700 Subject: [PATCH 0218/1224] adding REPL tests --- src/ScriptCs/Repl.cs | 50 +++---- test/ScriptCs.Tests/ReplTests.cs | 163 ++++++++++++++++++++++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 + 3 files changed, 189 insertions(+), 25 deletions(-) create mode 100644 test/ScriptCs.Tests/ReplTests.cs diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 2b289711..67a713b6 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -11,60 +11,60 @@ namespace ScriptCs { public class Repl { - private static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; + public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; - private readonly IFileSystem _fileSystem; - private readonly IScriptEngine _scriptEngine; - private readonly ILog _logger; - private readonly IConsole _console; - private ScriptPackSession _scriptPackSession; - private IEnumerable _references; + public IFileSystem FileSystem { get; private set; } + public IScriptEngine ScriptEngine { get; private set; } + public ILog Logger { get; private set; } + public IConsole Console { get; private set; } + public ScriptPackSession ScriptPackSession { get; private set; } + public IEnumerable References { get; private set; } public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console) { - _fileSystem = fileSystem; - _scriptEngine = scriptEngine; - _logger = logger; - _console = console; + FileSystem = fileSystem; + ScriptEngine = scriptEngine; + Logger = logger; + Console = console; } public void Initialize(IEnumerable paths, IEnumerable scriptPacks) { - _references = DefaultReferences.Union(paths); - var bin = Path.Combine(_fileSystem.CurrentDirectory, "bin"); + References = DefaultReferences.Union(paths); + var bin = Path.Combine(FileSystem.CurrentDirectory, "bin"); - _scriptEngine.BaseDirectory = bin; + ScriptEngine.BaseDirectory = bin; - _logger.Debug("Initializing script packs"); + Logger.Debug("Initializing script packs"); var scriptPackSession = new ScriptPackSession(scriptPacks); scriptPackSession.InitializePacks(); - _scriptPackSession = scriptPackSession; + ScriptPackSession = scriptPackSession; } public void Terminate() { - _logger.Debug("Terminating packs"); - _scriptPackSession.TerminatePacks(); + Logger.Debug("Terminating packs"); + ScriptPackSession.TerminatePacks(); } public void Execute(string script) { - var foregroundColor = _console.ForegroundColor; + var foregroundColor = Console.ForegroundColor; try { - _console.ForegroundColor = ConsoleColor.Cyan; - _scriptEngine.Execute(script, _references, DefaultNamespaces, _scriptPackSession); + Console.ForegroundColor = ConsoleColor.Cyan; + ScriptEngine.Execute(script, References, DefaultNamespaces, ScriptPackSession); } catch (Exception ex) { - _console.ForegroundColor = ConsoleColor.Red; - _console.WriteLine("\r\n" + ex + "\r\n"); + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("\r\n" + ex + "\r\n"); } - _console.ForegroundColor = foregroundColor; + Console.ForegroundColor = foregroundColor; } } } diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs new file mode 100644 index 00000000..a7065ac3 --- /dev/null +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Common.Logging; +using Moq; +using ScriptCs.Contracts; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class ReplTests + { + public class Mocks + { + public Mocks() + { + FileSystem = new Mock(); + ScriptEngine = new Mock(); + Logger = new Mock(); + Console = new Mock(); + ScriptPack = new Mock(); + } + + public Mock FileSystem { get; private set; } + public Mock ScriptEngine { get; private set; } + public Mock Logger { get; private set; } + public Mock Console { get; private set; } + public Mock ScriptPack { get; private set; } + } + + public static Repl GetRepl(Mocks mocks) + { + return new Repl(mocks.FileSystem.Object, mocks.ScriptEngine.Object, mocks.Logger.Object, mocks.Console.Object); + } + + public class TheConstructor + { + [Fact] + public void ShouldProperlyInitializeMembers() + { + var mocks = new Mocks(); + var repl = GetRepl(mocks); + repl.FileSystem.ShouldEqual(mocks.FileSystem.Object); + repl.ScriptEngine.ShouldEqual(mocks.ScriptEngine.Object); + repl.Logger.ShouldEqual(mocks.Logger.Object); + repl.Console.ShouldEqual(mocks.Console.Object); + } + } + + public class TheInitializeMethod + { + private Mocks _mocks; + private Repl _repl; + + public TheInitializeMethod() + { + _mocks = new Mocks(); + _repl = GetRepl(_mocks); + _mocks.FileSystem.Setup(x => x.CurrentDirectory).Returns(@"c:\"); + var paths = new []{@"c:\path"}; + _repl.Initialize(paths, new[] {_mocks.ScriptPack.Object}); + } + + [Fact] + public void PopulatesReferences() + { + foreach (var reference in Repl.DefaultReferences) + { + _repl.References.ShouldContain(reference); + } + _repl.References.ShouldContain(@"c:\path"); + } + + [Fact] + public void SetsTheScriptEngineBaseDirectory() + { + _mocks.ScriptEngine.VerifySet(x=>x.BaseDirectory = @"c:\bin"); + } + + [Fact] + public void CreatesTheScriptPackSession() + { + _repl.ScriptPackSession.ShouldNotBeNull(); + } + + [Fact] + public void InitializesScriptPacks() + { + _mocks.ScriptPack.Verify(x=>x.Initialize(It.IsAny())); + } + } + + public class TheTerminateMethod + { + private Mocks _mocks; + private Repl _repl; + + public TheTerminateMethod() + { + _mocks = new Mocks(); + _repl = GetRepl(_mocks); + _mocks.FileSystem.Setup(x => x.CurrentDirectory).Returns(@"c:\"); + _repl.Initialize(new List(), new[] {_mocks.ScriptPack.Object}); + _repl.Terminate(); + } + + [Fact] + public void TerminatesScriptPacks() + { + _mocks.ScriptPack.Verify(x => x.Terminate()); + } + } + + public class TheExecuteMethod + { + private Mocks _mocks; + private Repl _repl; + + public TheExecuteMethod() + { + _mocks = new Mocks(); + _repl = GetRepl(_mocks); + _repl.Console.ForegroundColor = ConsoleColor.White; + _repl.Execute("foo"); + } + + [Fact] + public void SetsTheForegroundColorToCyan() + { + _mocks.Console.VerifySet(x=>x.ForegroundColor = ConsoleColor.Cyan, Times.Once()); + } + + [Fact] + public void CallExecuteOnTheScriptEngine() + { + _mocks.ScriptEngine.Verify(x=>x.Execute("foo", _repl.References, Repl.DefaultNamespaces, It.IsAny())); + } + + [Fact] + public void CatchesExceptionsAndWritesThemInRed() + { + _mocks.ScriptEngine.Setup( + x => x.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())) + .Throws(); + + _repl.Execute("foo"); + + _mocks.Console.VerifySet(x => x.ForegroundColor = ConsoleColor.Red); + _mocks.Console.Verify(x => x.WriteLine(It.IsAny())); + + } + + [Fact] + public void SetsTheForegroundColorBackToTheDefault() + { + _mocks.Console.VerifySet(x=>x.ForegroundColor = ConsoleColor.White); + } + } + } +} diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index bfd05350..a7d14f0b 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -42,6 +42,7 @@ + From 3d7b21e5a5ec618e677631b66b105b9482b4f6d9 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 7 May 2013 22:41:47 -0700 Subject: [PATCH 0219/1224] fix typo --- test/ScriptCs.Tests/ReplTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index a7065ac3..5512d238 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -134,7 +134,7 @@ public void SetsTheForegroundColorToCyan() } [Fact] - public void CallExecuteOnTheScriptEngine() + public void CallsExecuteOnTheScriptEngine() { _mocks.ScriptEngine.Verify(x=>x.Execute("foo", _repl.References, Repl.DefaultNamespaces, It.IsAny())); } From bada79e3e4f2849764184643c069d768b97cd468 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 7 May 2013 23:44:29 -0700 Subject: [PATCH 0220/1224] Adding outputting return values --- src/ScriptCs.Core/IScriptEngine.cs | 2 +- .../RoslynScriptDebuggerEngine.cs | 5 +++-- src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs | 9 +++++---- src/ScriptCs/Repl.cs | 10 +++++++++- src/ScriptCs/ScriptCs.csproj | 3 +++ src/ScriptCs/packages.config | 1 + .../RoslynScriptEngineTests.cs | 3 ++- 7 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index 698d33e7..e22ab9c5 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -5,6 +5,6 @@ namespace ScriptCs public interface IScriptEngine { string BaseDirectory { get; set; } - void Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); + object Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index c0ce132c..51fdff79 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -20,7 +20,7 @@ public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory, ILog log this._logger = logger; } - protected override void Execute(string code, Session session) + protected override object Execute(string code, Session session) { _logger.Debug("Compiling submission"); var submission = session.CompileSubmission(code); @@ -59,7 +59,7 @@ protected override void Execute(string code, Session session) try { _logger.Debug("Invoking method."); - method.Invoke(null, new[] { session }); + return method.Invoke(null, new[] { session }); } catch (Exception e) { @@ -73,6 +73,7 @@ protected override void Execute(string code, Session session) throw new ScriptExecutionException(message); } } + return null; } } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ddafd230..ed572e18 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -28,7 +28,7 @@ public string BaseDirectory set { _scriptEngine.BaseDirectory = value; } } - public void Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) + public object Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { _logger.Info("Starting to create execution components"); _logger.Debug("Creating script host"); @@ -61,13 +61,14 @@ public void Execute(string code, IEnumerable references, IEnumerableFalse ..\..\packages\PowerArgs.1.5.0.0\lib\net40\PowerArgs.dll + + ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll + diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index a0ff3d6d..6ceb7925 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -6,4 +6,5 @@ + \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 9762edb8..242452d5 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -23,9 +23,10 @@ public TestRoslynScriptEngine(IScriptHostFactory scriptHostFactory, ILog logger) public Session Session { get; set; } - protected override void Execute(string code, Session session) + protected override object Execute(string code, Session session) { Session = session; + return null; } } From 4ec5e25b6f6977d068bd2760095140a4bc48d70a Mon Sep 17 00:00:00 2001 From: Filip W Date: Wed, 8 May 2013 09:49:55 -0400 Subject: [PATCH 0221/1224] added REPL #load and #r tests, and refactored #load and #r check from ExecuteReplCommand to Repl Execute --- src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs.Core/SessionState.cs | 10 ++++ .../RoslynScriptEngine.cs | 23 ++++----- src/ScriptCs/Command/ExecuteReplCommand.cs | 14 +----- src/ScriptCs/Repl.cs | 23 ++++++--- .../RoslynScriptEngineTests.cs | 22 ++++++++- test/ScriptCs.Tests/ReplTests.cs | 49 ++++++++++++++++++- 7 files changed, 104 insertions(+), 38 deletions(-) create mode 100644 src/ScriptCs.Core/SessionState.cs diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 48d287f0..adf91081 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -77,6 +77,7 @@ + diff --git a/src/ScriptCs.Core/SessionState.cs b/src/ScriptCs.Core/SessionState.cs new file mode 100644 index 00000000..2ab4651f --- /dev/null +++ b/src/ScriptCs.Core/SessionState.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public class SessionState + { + public T Session { get; set; } + public IEnumerable References { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index e2947216..f310d074 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -34,14 +34,14 @@ public void Execute(string code, IEnumerable references, IEnumerable sessionState; + if (!scriptPackSession.State.ContainsKey(SessionKey)) { var host = _scriptHostFactory.CreateScriptHost(new ScriptPackManager(scriptPackSession.Contexts)); _logger.Debug("Creating session"); var session = _scriptEngine.CreateSession(host); - + foreach (var reference in distinctReferences) { _logger.DebugFormat("Adding reference to {0}", reference); @@ -54,22 +54,23 @@ public void Execute(string code, IEnumerable references, IEnumerable {References = distinctReferences, Session = session}; + scriptPackSession.State[SessionKey] = sessionState; } else { _logger.Debug("Reusing existing session"); - sessionState = (SessionState)scriptPackSession.State[SessionKey]; + sessionState = (SessionState) scriptPackSession.State[SessionKey]; - var newReferences = distinctReferences.Except(sessionState.References); + var newReferences = sessionState.References == null || !sessionState.References.Any() ? distinctReferences : distinctReferences.Except(sessionState.References); if (newReferences.Any()) { - foreach (var reference in distinctReferences) + foreach (var reference in newReferences) { _logger.DebugFormat("Adding reference to {0}", reference); sessionState.Session.AddReference(reference); } + sessionState.References = newReferences; } } @@ -82,11 +83,5 @@ protected virtual void Execute(string code, Session session) { session.Execute(code); } - - private class SessionState - { - public Session Session { get; set; } - public IEnumerable References { get; set; } - } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index b05d91bd..13cd792b 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -38,7 +38,7 @@ IConsole console public CommandResult Execute() { Console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); - var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console); + var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console, _filePreProcessor); repl.Initialize(GetAssemblyPaths(_fileSystem.CurrentDirectory), _scriptPackResolver.GetPacks()); try { @@ -62,18 +62,6 @@ private bool ExecuteLine(Repl repl) if (line == "") return false; - if (PreProcessorUtil.IsLoadLine(line)) - { - var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); - line = _filePreProcessor.ProcessFile(filepath); - } - else if (PreProcessorUtil.IsRLine(line)) - { - var assemblyPath = PreProcessorUtil.GetPath(PreProcessorUtil.RString, line); - repl.AddReference(assemblyPath); - return true; - } - repl.Execute(line); return true; } diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index ca6dd762..8d39a66b 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.IO; using Common.Logging; using ScriptCs.Contracts; @@ -16,15 +14,17 @@ public class Repl public IFileSystem FileSystem { get; private set; } public IScriptEngine ScriptEngine { get; private set; } + public IFilePreProcessor FilePreProcessor { get; private set; } public ILog Logger { get; private set; } public IConsole Console { get; private set; } public ScriptPackSession ScriptPackSession { get; private set; } public IEnumerable References { get; private set; } - public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console) + public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console, IFilePreProcessor filePreProcessor) { FileSystem = fileSystem; ScriptEngine = scriptEngine; + FilePreProcessor = filePreProcessor; Logger = logger; Console = console; } @@ -44,11 +44,6 @@ public void Initialize(IEnumerable paths, IEnumerable scrip } - public void AddReference(string assembly) - { - _references = _references.Union(new[] { assembly }); - } - public void Terminate() { Logger.Debug("Terminating packs"); @@ -61,6 +56,18 @@ public void Execute(string script) try { + if (PreProcessorUtil.IsLoadLine(script)) + { + var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, script); + script = FilePreProcessor.ProcessFile(filepath); + } + else if (PreProcessorUtil.IsRLine(script)) + { + var assemblyPath = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); + References = References.Union(new[] { assemblyPath }); + return; + } + Console.ForegroundColor = ConsoleColor.Cyan; ScriptEngine.Execute(script, References, DefaultNamespaces, ScriptPackSession); } diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 9762edb8..6e68885d 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -81,10 +81,10 @@ public void ShouldReuseExistingSessionIfProvided() var engine = CreateTestScriptEngine(scriptHostFactory: scriptHostFactory); var scriptPackSession = new ScriptPackSession(new List()); var roslynEngine = new ScriptEngine(); - var session = roslynEngine.CreateSession(); + var session = new SessionState {Session = roslynEngine.CreateSession()}; scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); - engine.Session.ShouldEqual(session); + engine.Session.ShouldEqual(session.Session); } [Fact] @@ -100,6 +100,24 @@ public void ShouldCreateNewSessionIfNotProvided() engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); engine.Session.ShouldNotBeNull(); } + + [Fact] + public void ShouldAddNewReferencesIfTheyAreProvided() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + + var code = "var a = 0;"; + + var engine = CreateTestScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession()}; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + engine.Execute(code, new[] {"System"}, Enumerable.Empty(), scriptPackSession); + + ((SessionState)scriptPackSession.State[RoslynScriptEngine.SessionKey]).References.Count().ShouldEqual(1); + } } } } \ No newline at end of file diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 5512d238..248040dd 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -22,6 +22,7 @@ public Mocks() Logger = new Mock(); Console = new Mock(); ScriptPack = new Mock(); + FilePreProcessor = new Mock(); } public Mock FileSystem { get; private set; } @@ -29,11 +30,12 @@ public Mocks() public Mock Logger { get; private set; } public Mock Console { get; private set; } public Mock ScriptPack { get; private set; } + public Mock FilePreProcessor { get; private set; } } public static Repl GetRepl(Mocks mocks) { - return new Repl(mocks.FileSystem.Object, mocks.ScriptEngine.Object, mocks.Logger.Object, mocks.Console.Object); + return new Repl(mocks.FileSystem.Object, mocks.ScriptEngine.Object, mocks.Logger.Object, mocks.Console.Object, mocks.FilePreProcessor.Object); } public class TheConstructor @@ -158,6 +160,51 @@ public void SetsTheForegroundColorBackToTheDefault() { _mocks.Console.VerifySet(x=>x.ForegroundColor = ConsoleColor.White); } + + [Fact] + public void ShouldProcessFileIfLineIsALoad() + { + var mocks = new Mocks(); + _repl = GetRepl(mocks); + _repl.Execute("#load \"file.csx\""); + + mocks.FilePreProcessor.Verify(i => i.ProcessFile(It.Is(x => x == "file.csx")), Times.Once()); + } + + [Fact] + public void ShouldExecuteLoadedFileIfLineIsALoad() + { + var mocks = new Mocks(); + _repl = GetRepl(mocks); + _repl.Execute("#load \"file.csx\""); + + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); + } + + [Fact] + public void ShouldReferenceAssemblyIfLineIsAReference() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"my.dll\""); + + //default references = 6, + 1 we just added + _repl.References.Count().ShouldEqual(7); + } + + [Fact] + public void ShouldNotExecuteAnythingIfLineIsAReference() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"my.dll\""); + + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); + } } } } From 1bc41e7ad9399766294f0e653ed8dd1b2a2e0d22 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Fri, 10 May 2013 08:46:14 -0400 Subject: [PATCH 0222/1224] scriptcs Chocolatey package should depend on the NuGet.CommandLine package --- src/ScriptCs/Properties/chocolateyInstall.ps1 | 2 +- src/ScriptCs/Properties/scriptcs.nuspec | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/Properties/chocolateyInstall.ps1 b/src/ScriptCs/Properties/chocolateyInstall.ps1 index 68598df8..c8c1caba 100644 --- a/src/ScriptCs/Properties/chocolateyInstall.ps1 +++ b/src/ScriptCs/Properties/chocolateyInstall.ps1 @@ -14,7 +14,7 @@ "Roslyn.Compilers.CSharp" = "1.2.20906.2"; } - $dependencies.GetEnumerator() | %{ .$nuget install $_.Name -version $_.Value -o $nugetPath } + $dependencies.GetEnumerator() | %{ &nuget install $_.Name -version $_.Value -o $nugetPath } Get-ChildItem $nugetPath -Filter "*.dll" -Recurse | %{ Copy-Item $_.FullName $binPath -Force } Remove-Item $nugetPath -Recurse -Force diff --git a/src/ScriptCs/Properties/scriptcs.nuspec b/src/ScriptCs/Properties/scriptcs.nuspec index 813821b9..d2c38861 100644 --- a/src/ScriptCs/Properties/scriptcs.nuspec +++ b/src/ScriptCs/Properties/scriptcs.nuspec @@ -13,11 +13,15 @@ + + + + From a48ff24f9af76c40b38dcbb7d97862ad2fd67ac1 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 10 May 2013 19:04:27 +0200 Subject: [PATCH 0223/1224] Cleaned up Main method --- src/ScriptCs/CompositionRoot.cs | 13 ++++-- src/ScriptCs/Program.cs | 78 ++++++++++++++------------------- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 086091da..0ef465dd 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -18,11 +18,11 @@ public class CompositionRoot private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; - public CompositionRoot(bool debug, bool useDirectoryCatalog, LogLevel logLevel) + public CompositionRoot(ScriptCsArgs args) { - _debug = debug; - _logLevel = logLevel; - _shouldInitDrirectoryCatalog = useDirectoryCatalog; + _debug = args.DebugFlag; + _logLevel = args.LogLevel; + _shouldInitDrirectoryCatalog = ShouldInitDrirectoryCatalog(args); } public void Initialize() @@ -85,5 +85,10 @@ public ILog GetLogger() { return _container.Resolve(); } + + private static bool ShouldInitDrirectoryCatalog(ScriptCsArgs args) + { + return args.Repl || !string.IsNullOrWhiteSpace(args.ScriptName); + } } } \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index f04a7d58..f2f3629d 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,54 +1,20 @@ -using Common.Logging; +using System; + using PowerArgs; using ScriptCs.Command; namespace ScriptCs { - using System; - - internal class Program + internal static class Program { private static int Main(string[] args) { - ILog logger = null; - ScriptCsArgs commandArgs = null; - - const string unexpectedArgumentMessage = "Unexpected Argument: "; - - if (args.Length > 0) - { - try - { - commandArgs = Args.Parse(args); - } - catch (ArgException ex) - { - commandArgs = new ScriptCsArgs(); + var commandArgs = ParseArguments(args) ?? new ScriptCsArgs { Repl = true }; - if (ex.Message.StartsWith(unexpectedArgumentMessage)) - { - var token = ex.Message.Substring(unexpectedArgumentMessage.Length); - Console.WriteLine("Parameter \"{0}\" is not supported!", token); - } - else - { - Console.WriteLine(ex.Message); - } - } - } - - if (commandArgs == null) - { - commandArgs = new ScriptCsArgs() {Repl = true}; - } - - var debug = commandArgs.DebugFlag; - var logLevel = commandArgs.LogLevel; - var scriptProvided = !string.IsNullOrWhiteSpace(commandArgs.ScriptName) || commandArgs.Repl; - - var compositionRoot = new CompositionRoot(debug, scriptProvided, logLevel); + var compositionRoot = new CompositionRoot(commandArgs); compositionRoot.Initialize(); - logger = compositionRoot.GetLogger(); + + var logger = compositionRoot.GetLogger(); logger.Debug("Creating ScriptServiceRoot"); var scriptServiceRoot = compositionRoot.GetServiceRoot(); @@ -57,13 +23,33 @@ private static int Main(string[] args) var command = commandFactory.CreateCommand(commandArgs); var result = command.Execute(); - switch (result) + return result == CommandResult.Success ? 0 : -1; + } + + private static ScriptCsArgs ParseArguments(string[] args) + { + const string UnexpectedArgumentMessage = "Unexpected Argument: "; + + if (args.Length <= 0) return null; + + try + { + return Args.Parse(args); + } + catch (ArgException ex) { - case CommandResult.Success: - return 0; - default: - return -1; + if (ex.Message.StartsWith(UnexpectedArgumentMessage)) + { + var token = ex.Message.Substring(UnexpectedArgumentMessage.Length); + Console.WriteLine("Parameter \"{0}\" is not supported!", token); + } + else + { + Console.WriteLine(ex.Message); + } } + + return new ScriptCsArgs(); } } } \ No newline at end of file From 77b9a2d15d38a1033da1fd54e730ba4f12887123 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 10 May 2013 19:23:20 +0200 Subject: [PATCH 0224/1224] Disabled type and position in usage. Merge HelpCommand and InvalidCommand into ShowUsageCommand --- src/ScriptCs/Command/CommandFactory.cs | 5 ++-- src/ScriptCs/Command/HelpCommand.cs | 26 ------------------- src/ScriptCs/Command/InvalidCommand.cs | 21 --------------- src/ScriptCs/Command/ShowUsageCommand.cs | 33 ++++++++++++++++++++++++ src/ScriptCs/ScriptCs.csproj | 7 +++-- src/ScriptCs/packages.config | 2 +- 6 files changed, 39 insertions(+), 55 deletions(-) delete mode 100644 src/ScriptCs/Command/HelpCommand.cs delete mode 100644 src/ScriptCs/Command/InvalidCommand.cs create mode 100644 src/ScriptCs/Command/ShowUsageCommand.cs diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index bb9a1452..ef22c95b 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -1,5 +1,4 @@ using System.IO; -using ScriptCs.Engine.Roslyn; namespace ScriptCs.Command { @@ -16,7 +15,7 @@ public ICommand CreateCommand(ScriptCsArgs args) { if (args.Help) { - return new HelpCommand(_scriptServiceRoot.Logger); + return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: true); } if (args.Repl) @@ -101,7 +100,7 @@ public ICommand CreateCommand(ScriptCsArgs args) return new VersionCommand(); } - return new InvalidCommand(_scriptServiceRoot.Logger); + return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: false); } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/HelpCommand.cs b/src/ScriptCs/Command/HelpCommand.cs deleted file mode 100644 index f37b06f1..00000000 --- a/src/ScriptCs/Command/HelpCommand.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Common.Logging; -using PowerArgs; - -namespace ScriptCs.Command -{ - internal class HelpCommand : IHelpCommand - { - private readonly ILog _logger; - - public HelpCommand(ILog logger) - { - _logger = logger; - } - - public CommandResult Execute() - { - _logger.Info(ArgUsage.GetUsage()); - return CommandResult.Success; - } - } -} diff --git a/src/ScriptCs/Command/InvalidCommand.cs b/src/ScriptCs/Command/InvalidCommand.cs deleted file mode 100644 index 7028d9d3..00000000 --- a/src/ScriptCs/Command/InvalidCommand.cs +++ /dev/null @@ -1,21 +0,0 @@ -using PowerArgs; -using Common.Logging; - -namespace ScriptCs.Command -{ - internal class InvalidCommand : IInvalidCommand - { - private readonly ILog _logger; - - public InvalidCommand(ILog logger) - { - _logger = logger; - } - - public CommandResult Execute() - { - _logger.Error(ArgUsage.GetUsage()); - return CommandResult.Error; - } - } -} \ No newline at end of file diff --git a/src/ScriptCs/Command/ShowUsageCommand.cs b/src/ScriptCs/Command/ShowUsageCommand.cs new file mode 100644 index 00000000..ebf2bccb --- /dev/null +++ b/src/ScriptCs/Command/ShowUsageCommand.cs @@ -0,0 +1,33 @@ +using Common.Logging; +using PowerArgs; + +namespace ScriptCs.Command +{ + internal class ShowUsageCommand : IHelpCommand, IInvalidCommand + { + private readonly ILog _logger; + + private readonly bool _isValid; + + public ShowUsageCommand(ILog logger, bool isValid) + { + _logger = logger; + _isValid = isValid; + } + + public CommandResult Execute() + { + var options = new ArgUsageOptions { ShowPosition = false, ShowType = false }; + var usage = ArgUsage.GetUsage(options: options); + + if (_isValid) + { + _logger.Info(usage); + return CommandResult.Success; + } + + _logger.Error(usage); + return CommandResult.Error; + } + } +} diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 196453f6..e486e9d7 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -33,9 +33,9 @@ False ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll - + False - ..\..\packages\PowerArgs.1.5.0.0\lib\net40\PowerArgs.dll + ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll @@ -59,10 +59,9 @@ - + - diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index a0ff3d6d..9a38f4a2 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -5,5 +5,5 @@ - + \ No newline at end of file From 3cea168d2e457730e8283fc0b3bb6b8268c420a9 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 10 May 2013 12:05:30 -0600 Subject: [PATCH 0225/1224] Update CONTRIBUTING.md --- CONTRIBUTING.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b4c2c4a4..738b6164 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,34 @@ # Contributing -Before submitting a feature or substantial code contribution please discuss it with the team in our [discussion group](https://groups.google.com/forum/?fromgroups#!forum/scriptcs). +We've seen some great energy from folks around contributing to scriptcs and WE LOVE IT. scriptcs *welcomes* your contribuitions! In order to make it easy we've come up with the following model so that you can [Jump in](http://nikcodes.com/2013/05/10/new-contributor-jump-in/). The guidelines will help us all to operate in harmony. + +We definitely want to soak up all that energy you have! + +## The issue tracker and how you can contribute. + +* Bugs - For bugs, just go fix it. Don't ask UNLESS it starts to turn into a feature. +* Features - By default all issues tagged as enhancements will be fixed by the core team. However if you'd like to take it, please socialize the idea in our new google group (https://groups.google.com/forum/?fromgroups#!forum/scriptcs) so we can discuss before you put in a potentially wasted effort. +* YOU TAKE IT - These are items that are important, but which we'd available for the community to take. One place we use this is for investigations and prototyping for features that would be really awesome, but which the core team just don't have bandwith for. As an example @dschenkelman [investigated](https://github.com/scriptcs/scriptcs/issues/68?source=cc) a VS debugging story. This lead to him ultimately implementing the feature, however don't feel pressure that you have to that. It's extremely valuable if you can just show us how it might be done. + +A few other points: + +* If an issue is marked as "Taken" then it is assigned to another member of the community. +* To take an issue, reply in the comments "I'll take it" + +## Discussing features + +We'd like the design for all features to get socialized either via github issues or our [discussion group](https://groups.google.com/forum/?fromgroups#!forum/scriptcs). Please do this before you implement so that we can all get on the same page of the feature and not waste your time, which we really appreciate. + +## Summary: + +* unassigned bug - available for you +* assigned bug / taken bug - unavailable +* you take it issue - available for you +* taken issue - unavailable as someone already took it. + +We really appreciate your help in taking scriptcs forward! + +Before submitting a feature or substantial code contribution please discuss it with the team in our Also please see the discussion [here] on which things are open for contribution (https://github.com/scriptcs/scriptcs/issues/79) From 74a839d309e99344f34259baa7c2055d9a3d00b2 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 10 May 2013 12:55:57 -0600 Subject: [PATCH 0226/1224] Update CONTRIBUTING.md --- CONTRIBUTING.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b4c2c4a4..738b6164 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,34 @@ # Contributing -Before submitting a feature or substantial code contribution please discuss it with the team in our [discussion group](https://groups.google.com/forum/?fromgroups#!forum/scriptcs). +We've seen some great energy from folks around contributing to scriptcs and WE LOVE IT. scriptcs *welcomes* your contribuitions! In order to make it easy we've come up with the following model so that you can [Jump in](http://nikcodes.com/2013/05/10/new-contributor-jump-in/). The guidelines will help us all to operate in harmony. + +We definitely want to soak up all that energy you have! + +## The issue tracker and how you can contribute. + +* Bugs - For bugs, just go fix it. Don't ask UNLESS it starts to turn into a feature. +* Features - By default all issues tagged as enhancements will be fixed by the core team. However if you'd like to take it, please socialize the idea in our new google group (https://groups.google.com/forum/?fromgroups#!forum/scriptcs) so we can discuss before you put in a potentially wasted effort. +* YOU TAKE IT - These are items that are important, but which we'd available for the community to take. One place we use this is for investigations and prototyping for features that would be really awesome, but which the core team just don't have bandwith for. As an example @dschenkelman [investigated](https://github.com/scriptcs/scriptcs/issues/68?source=cc) a VS debugging story. This lead to him ultimately implementing the feature, however don't feel pressure that you have to that. It's extremely valuable if you can just show us how it might be done. + +A few other points: + +* If an issue is marked as "Taken" then it is assigned to another member of the community. +* To take an issue, reply in the comments "I'll take it" + +## Discussing features + +We'd like the design for all features to get socialized either via github issues or our [discussion group](https://groups.google.com/forum/?fromgroups#!forum/scriptcs). Please do this before you implement so that we can all get on the same page of the feature and not waste your time, which we really appreciate. + +## Summary: + +* unassigned bug - available for you +* assigned bug / taken bug - unavailable +* you take it issue - available for you +* taken issue - unavailable as someone already took it. + +We really appreciate your help in taking scriptcs forward! + +Before submitting a feature or substantial code contribution please discuss it with the team in our Also please see the discussion [here] on which things are open for contribution (https://github.com/scriptcs/scriptcs/issues/79) From 69a1326628ab9f0949c53569a42712774cc09267 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 11 May 2013 22:48:20 +0200 Subject: [PATCH 0227/1224] Renamed DebugFlag and AllowPreReleaseFlag arguments --- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/CompositionRoot.cs | 2 +- src/ScriptCs/ScriptCsArgs.cs | 30 ++++++++----------- test/ScriptCs.Tests/CommandFactoryTests.cs | 10 +++---- .../ExecuteScriptCommandTests.cs | 2 +- test/ScriptCs.Tests/InstallCommandTests.cs | 4 +-- 6 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index ef22c95b..280fef0c 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -53,7 +53,7 @@ public ICommand CreateCommand(ScriptCsArgs args) { var installCommand = new InstallCommand( args.Install, - args.AllowPreReleaseFlag, + args.AllowPreRelease, _scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.PackageInstaller, diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 0ef465dd..e327b61d 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -20,7 +20,7 @@ public class CompositionRoot public CompositionRoot(ScriptCsArgs args) { - _debug = args.DebugFlag; + _debug = args.Debug; _logLevel = args.LogLevel; _shouldInitDrirectoryCatalog = ShouldInitDrirectoryCatalog(args); } diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index cf120358..00e5ec66 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -1,8 +1,4 @@ -using System; -using System.Linq; - -using PowerArgs; -using System.Globalization; +using PowerArgs; namespace ScriptCs { @@ -12,8 +8,8 @@ public class ScriptCsArgs [ArgIgnore] public bool Repl { get; set; } - [ArgDescription("Script file name, must be specified first")] [ArgPosition(0)] + [ArgDescription("Script file name, must be specified first")] public string ScriptName { get; set; } [ArgDescription("Displays help")] @@ -21,37 +17,37 @@ public class ScriptCsArgs [ArgShortcut("?")] public bool Help { get; set; } - - [ArgDescription("Flag which switches on debug mode")] [ArgShortcut("debug")] - public bool DebugFlag { get; set; } + [ArgDescription("Flag which switches on debug mode")] + public bool Debug { get; set; } - [ArgDescription("Flag which defines the log level used.")] - [ArgShortcut("log")] [ArgIgnoreCase] + [ArgShortcut("log")] [DefaultValue(LogLevel.Info)] + [ArgDescription("Flag which defines the log level used.")] public LogLevel LogLevel { get; set; } - [ArgDescription("Installs and restores packages which are specified in packages.config")] [ArgShortcut("install")] + [ArgDescription("Installs and restores packages which are specified in packages.config")] public string Install { get; set; } - [ArgDescription("Restores installed packages, making them ready for using by the script")] [ArgShortcut("restore")] + [ArgDescription("Restores installed packages, making them ready for using by the script")] public bool Restore { get; set; } - [ArgDescription("Creates a packages.config file based on the packages directory")] [ArgShortcut("save")] + [ArgDescription("Creates a packages.config file based on the packages directory")] public bool Save { get; set; } - [ArgDescription("Cleans installed packages from working directory")] [ArgShortcut("clean")] + [ArgDescription("Cleans installed packages from working directory")] public bool Clean { get; set; } - [ArgDescription("Allows installation of packages' prelease versions")] [ArgShortcut("pre")] - public bool AllowPreReleaseFlag { get; set; } + [ArgDescription("Allows installation of packages' prelease versions")] + public bool AllowPreRelease { get; set; } + [ArgShortcut("version")] [ArgDescription("Outputs version information")] public bool Version { get; set; } } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 8c43816b..be5d5a5d 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -36,7 +36,7 @@ public void ShouldInstallAndRestoreWhenInstallFlagIsOn() { var args = new ScriptCsArgs { - AllowPreReleaseFlag = false, + AllowPreRelease = false, Install = "", ScriptName = null }; @@ -57,7 +57,7 @@ public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExist { var args = new ScriptCsArgs { - AllowPreReleaseFlag = false, + AllowPreRelease = false, Install = "", ScriptName = null }; @@ -79,7 +79,7 @@ public void ShouldExecuteWhenScriptNameIsPassed() { var args = new ScriptCsArgs { - AllowPreReleaseFlag = false, + AllowPreRelease = false, Install = null, ScriptName = "test.csx" }; @@ -95,7 +95,7 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() { var args = new ScriptCsArgs { - AllowPreReleaseFlag = false, + AllowPreRelease = false, Install = "", ScriptName = "test.csx" }; @@ -155,7 +155,7 @@ public void ShouldReturnInvalidWhenNoNameOrInstallSet() { var args = new ScriptCsArgs { - AllowPreReleaseFlag = false, + AllowPreRelease = false, Install = null, ScriptName = null }; diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 33ea21f7..ea7d3ebf 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -18,7 +18,7 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() { var args = new ScriptCsArgs { - AllowPreReleaseFlag = false, + AllowPreRelease = false, Install = "", ScriptName = "test.csx" }; diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 4c842058..ef8b140e 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -19,7 +19,7 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() { var args = new ScriptCsArgs { - AllowPreReleaseFlag = false, + AllowPreRelease = false, Install = "mypackage", ScriptName = null }; @@ -51,7 +51,7 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() { var args = new ScriptCsArgs { - AllowPreReleaseFlag = false, + AllowPreRelease = false, Install = "", ScriptName = null }; From e7d8eb3a7b359891d2813e82329ea7fffe71a7fa Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 12 May 2013 04:24:31 -0300 Subject: [PATCH 0228/1224] new quickstart updated readme to have an up to date quickstart! --- README.md | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 58291a9a..c187aa28 100644 --- a/README.md +++ b/README.md @@ -3,53 +3,46 @@ ## Why should you care? Write C# apps with a text editor, nuget and the power of Rosyln! -**Note**: *Rosyln is a pre-release CTP and currently an unsupported technology. As such there may be changes in Roslyn itself that could impact this project. Please bear that in mind when using scriptcs* +**Note**: *Roslyn is a pre-release CTP and currently an unsupported technology. As such there may be changes in Roslyn itself that could impact this project. Please bear that in mind when using scriptcs* * More on why I developed this [here] (http://codebetter.com/glennblock/2013/02/28/scriptcs-living-on-the-edge-in-c-without-a-project-on-the-wings-of-roslyn-and-nuget/) * Check out our goals and rodmap [here] (https://github.com/scriptcs/scriptcs/wiki/Project-goals-and-roadmap) ## Pre-reqs -* Install the [nuget cmdline bootstrapper] (http://nuget.codeplex.com/releases/view/58939) -* Build the project and put scriptcs.exe in your path. +* Install scriptcs from Chocolatey `cinst scriptcs` or +* Build the project from the source and put `scriptcs.exe` in your path. ## Quick start * Open a cmd prompt as admin -* Create a directory "c:\scriptcs_hello" and change to it. -* run "nuget install Microsoft.AspNet.WebApi.SelfHost -o Packages" -* create a server.csx with your favorite editor. Paste the text below into the file and save. +* run `scriptcs -install scriptcs.webapi` +* create a `server.csx` with your favorite editor. Paste the text below into the file and save (notice no namespaces & no top level class). ```csharp -using System; -using System.IO; -using System.Web.Http; -using System.Web.Http.SelfHost; - -var address = "http://localhost:8080"; -var conf = new HttpSelfHostConfiguration(new Uri(address)); -conf.Routes.MapHttpRoute(name: "DefaultApi", - routeTemplate: "api/{controller}/{id}", - defaults: new { id = RouteParameter.Optional } -); - -var server = new HttpSelfHostServer(conf); +public class TestController : ApiController { + public string Get() { + return "Hello world!"; + } +} + +var webApi = Require(); +var server = webApi.CreateServer("http://localhost:8080"); server.OpenAsync().Wait(); + Console.WriteLine("Listening..."); Console.ReadKey(); +server.CloseAsync().Wait(); ``` -* run "scriptcs server.csx" +* run `scriptcs server.csx` -This will launch a web api host. +This will launch a web api host with a sample controller, which you can access from the browser. ## How it works -scriptcs relies on Rosyln for loading loose C# script files. It will automatically discover nuget packages local to the app and load the binaries. +scriptcs relies on Roslyn for loading loose C# script files. It will automatically discover nuget packages local to the app and load the binaries. ## Docs * [Referencing other scripts from your script](https://github.com/scriptcs/scriptcs/wiki/Referencing-scripts) * [Debugging overview & How To](https://github.com/scriptcs/scriptcs/blob/dev/docs/DEBUGGING.md) -## What's next -* Adding support for pluggable recipe "packs" for different frameworks. - ## Contributing * Read our [Contribution Guidelines](https://github.com/scriptcs/scriptcs/blob/master/CONTRIBUTING.md). * List of all [contributors to date](https://github.com/scriptcs/scriptcs/wiki/Contributors). Thanks! From a4d4fad219ee446f050186e0988cdbd70799343e Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 12 May 2013 22:22:08 -0300 Subject: [PATCH 0229/1224] Rewrite README.md --- README.md | 255 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 205 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 58291a9a..546db994 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,226 @@ # scriptcs -## Why should you care? -Write C# apps with a text editor, nuget and the power of Rosyln! - -**Note**: *Rosyln is a pre-release CTP and currently an unsupported technology. As such there may be changes in Roslyn itself that could impact this project. Please bear that in mind when using scriptcs* - -* More on why I developed this [here] (http://codebetter.com/glennblock/2013/02/28/scriptcs-living-on-the-edge-in-c-without-a-project-on-the-wings-of-roslyn-and-nuget/) -* Check out our goals and rodmap [here] (https://github.com/scriptcs/scriptcs/wiki/Project-goals-and-roadmap) - -## Pre-reqs -* Install the [nuget cmdline bootstrapper] (http://nuget.codeplex.com/releases/view/58939) -* Build the project and put scriptcs.exe in your path. - -## Quick start -* Open a cmd prompt as admin -* Create a directory "c:\scriptcs_hello" and change to it. -* run "nuget install Microsoft.AspNet.WebApi.SelfHost -o Packages" -* create a server.csx with your favorite editor. Paste the text below into the file and save. - -```csharp -using System; -using System.IO; -using System.Web.Http; -using System.Web.Http.SelfHost; - -var address = "http://localhost:8080"; -var conf = new HttpSelfHostConfiguration(new Uri(address)); -conf.Routes.MapHttpRoute(name: "DefaultApi", - routeTemplate: "api/{controller}/{id}", - defaults: new { id = RouteParameter.Optional } -); - -var server = new HttpSelfHostServer(conf); + +## What is it? + +scriptcs makes it easy to write and execute C# with a simple text editor. + +While Visual Studio, and other IDEs, are powerful tools, they can sometimes hinder productivity more than they promote it. You don’t always need, or want, the overhead of a creating a new solution or project. Sometimes you want to just type away in your favorite text editor. + +scriptcs frees you from Visual Studio, without sacrificing the advantages of a strongly-typed language. + +* Write C# in your favorite text editor. +* Use NuGet to manage your dependencies. +* The relaxed C# scripting syntax means you can write and execute an application with only one line of code. +* Script Packs allow you to bootstrap the environment for new scripts, further reduces the amount of code necessary to take advantage of your favorite C# frameworks. + + +## Getting scriptcs + +Releases and nightly builds should be installed using [Chocolatey](http://chocolatey.org/). To install Chocolatey, execute the following command in your command prompt: + + @powershell -NoProfile -ExecutionPolicy Unrestricted -Command "iex ((New-Object Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin + +### Installing scriptcs + +Once Chocolatey has been installed, you can install the latest stable version of scriptcs from your command prompt: + + cinst scriptcs + +Chocolatey will install scriptcs to `%APPDATA%\scriptcs\` and update your PATH accordingly. + +**Note:** You may need to restart your command prompt after the installation completes. + +### Staying up-to-date + +With Chocolatey, keeping scriptcs updated is just as easy: + + cup scriptcs + +### Nightly builds + +Nightly builds are hosted on [MyGet](https://www.myget.org/), and can also be installed through with Chocolatey: + + cinst scriptcs -pre -source https://www.myget.org/F/scriptcsnightly/ + +### Building from source + +Execute `build.cmd` to start the build script. + + +## Getting Started + +### Using the REPL +The scriptcs REPL can be started by running scriptcs without any parameters. The REPL allows you to execute C# statements directly from your command prompt. + +```batchfile +C:\> scriptcs +scriptcs (ctrl-c or blank to exit) + +> var message = "Hello, world!"; +> Console.WriteLine(message); +Hello, world! +> + +C:\> +``` + +### Writing a script + +* In an empty directory, create a new file named `app.csx`: + +```c# +using Raven.Client; +using Raven.Client.Embedded; +using Raven.Client.Indexes; + +Console.WriteLine("Starting RavenDB server..."); + +EmbeddableDocumentStore documentStore = null; +try +{ + documentStore = new EmbeddableDocumentStore { UseEmbeddedHttpServer = true }; + documentStore.Initialize(); + + var url = string.Format("http://localhost:{0}", documentStore.Configuration.Port); + Console.WriteLine("RavenDB started, listening on {0}.", url); + + Console.ReadKey(); +} +finally +{ + if (documentStore != null) + documentStore.Dispose(); +} +``` + +* Install the [RavenDB.Embedded](https://nuget.org/packages/RavenDB.Embedded/) package from NuGet using the [install command](https://github.com/scriptcs/scriptcs/wiki/Package-installation). + +```batchfile +scriptcs -install RavenDB.Embedded +``` + +* Execute your script. Note that listening on a port requires that the command prompt be launched using the **Run as Administrator** option. + +```batchfile +> scriptcs app.csx +INFO : Starting to create execution components +INFO : Starting execution +Starting RavenDB server... +.. snip .. +RavenDB started, listening on http://localhost:8080. +``` + +* Navigating to the URL that Raven is listening on will now bring up the RavenDB management studio. + +### Bootstrap scripts with Script Packs + +Script Packs can be used to further reduce the amount of code you need to write when working with common frameworks. + +* In an empty directory, install the [ScriptCs.WebApi](https://nuget.org/packages/ScriptCs.WebApi/) script pack from NuGet. The script pack will automatically imports the Web API namespaces and provides a convenient factory method for initializing the Web API host. It also replaces the default `ControllerResolver` with a custom implementation that allows Web API to discover controllers declared in scripts. + +```batchfile +scriptcs -install ScriptCs.WebApi +``` + +* Script packs can be imported into a script by calling `Require()`. Create a file named `server.csx` that contains the following code: + +```c# +public class TestController : ApiController { + public string Get() { + return "Hello world!"; + } +} + +var webApi = Require(); +var server = webApi.CreateServer("http://localhost:8888"); server.OpenAsync().Wait(); + Console.WriteLine("Listening..."); Console.ReadKey(); +server.CloseAsync().Wait(); +``` + +* In a command prompt running as administrator, execute the `server.csx` file. + +```batchfile +scriptcs server.csx +``` + +* Browse to http://localhost:8888/test/ to see the result of the TestController.Get method. + +```xml +Hello world! ``` -* run "scriptcs server.csx" -This will launch a web api host. +### Referencing scripts -## How it works -scriptcs relies on Rosyln for loading loose C# script files. It will automatically discover nuget packages local to the app and load the binaries. +* Move the TestController class from the previous example into a new file named `controller.csx` with the following content. -## Docs -* [Referencing other scripts from your script](https://github.com/scriptcs/scriptcs/wiki/Referencing-scripts) -* [Debugging overview & How To](https://github.com/scriptcs/scriptcs/blob/dev/docs/DEBUGGING.md) +* On the first line of `server.csx`, reference `controller.csx` using the [#load directive](https://github.com/scriptcs/scriptcs/wiki/Writing-a-script#loading-referenced-scripts). **Note:** #load directives must be placed at the top of a script, otherwise they will be ignored. + +``` +#load "controller.csx" +``` + +* In a command prompt running as administrator, execute the `server.csx` file. + +```batchfile +scriptcs server.csx +``` + +* Browse to http://localhost:8888/test/ to see the result of the TestController.Get method. + +```xml +Hello world! +``` + + +### Referencing assemblies + +You can reference additional assemblies from the GAC or from the bin folder in your script's directory using the [#r directive](https://github.com/scriptcs/scriptcs/wiki/Writing-a-script#referencing-assemblies): + +``` +#r "nunit.core.dll" +#r "nunit.core.interfaces.dll" + +var path = "UnitTests.dll"; +var runner = TestSetup.GetRunner(new[] {path}); +var result = runner.Run(new ConsoleListener(msg => Console.WriteLine(msg)), TestFilter.Empty, true, LoggingThreshold.All); + +Console.ReadKey(); +``` -## What's next -* Adding support for pluggable recipe "packs" for different frameworks. ## Contributing + * Read our [Contribution Guidelines](https://github.com/scriptcs/scriptcs/blob/master/CONTRIBUTING.md). -* List of all [contributors to date](https://github.com/scriptcs/scriptcs/wiki/Contributors). Thanks! -## Credits -* Special thanks to [@filip_woj](http://twitter.com/filip_woj) for being the inspiration behind this with his Roslyn Web API posts. -* Thanks to the Roslyn team who helped point me in the right direction. -## Coordinators -* Glenn Block ([@gblock](https://twitter.com/gblock)) -* Justin Rusbatch ([@jrusbatch](https://twitter.com/jrusbatch)) -* Filip Wojcieszyn ([@filip_woj](https://twitter.com/filip_woj)) +## Samples and Documentation + +Additional samples can be contributed to our [samples repository](https://github.com/scriptcs/scriptcs-samples). Documentation can be found on our [wiki](https://github.com/scriptcs/scriptcs/wiki). + ## Community + Want to chat? In addition to Twitter, you can find us on [Google Groups](https://groups.google.com/forum/?fromgroups#!forum/scriptcs) and [JabbR](https://jabbr.net/#/rooms/scriptcs)! + +## Coordinators + +* [Glenn Block](https://github.com/glennblock) ([@gblock](https://twitter.com/intent/user?screen_name=gblock)) +* [Justin Rusbatch](https://github.com/jrusbatch) ([@jrusbatch](https://twitter.com/intent/user?screen_name=jrusbatch)) +* [Filip Wojcieszyn](https://github.com/filipw) ([@filip_woj](https://twitter.com/intent/user?screen_name=filip_woj)) + + +## Credits + +* Check out the [list of developers](https://github.com/scriptcs/scriptcs/wiki/Contributors) responsible for getting scriptcs to where it is today! +* Special thanks to Filip Wojcieszyn for being the inspiration behind this with his Roslyn Web API posts. +* Thanks to the Roslyn team who helped point me in the right direction. + + ## License -[Apache 2 License](https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md) +[Apache 2 License](https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md) From b262cd67f52d7c1f71eb217b6ab5d4bcbb0d1ac9 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 12 May 2013 21:23:20 -0400 Subject: [PATCH 0230/1224] Specify language for syntax highlighting in code blocks --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 546db994..546650c2 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ scriptcs server.csx * On the first line of `server.csx`, reference `controller.csx` using the [#load directive](https://github.com/scriptcs/scriptcs/wiki/Writing-a-script#loading-referenced-scripts). **Note:** #load directives must be placed at the top of a script, otherwise they will be ignored. -``` +```c# #load "controller.csx" ``` @@ -180,7 +180,7 @@ scriptcs server.csx You can reference additional assemblies from the GAC or from the bin folder in your script's directory using the [#r directive](https://github.com/scriptcs/scriptcs/wiki/Writing-a-script#referencing-assemblies): -``` +```c# #r "nunit.core.dll" #r "nunit.core.interfaces.dll" From 756f683994a1e49184e2d53334af04254ffaf14f Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 12 May 2013 21:26:52 -0400 Subject: [PATCH 0231/1224] Bump version number to v0.4.0 --- build/ScriptCs.Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index c4a3e643..7dae5744 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -9,7 +9,7 @@ - alpha + From ddea77a806f3d9360178824935b7133f0b802310 Mon Sep 17 00:00:00 2001 From: Adam Ralph Date: Sun, 12 May 2013 14:19:47 +0200 Subject: [PATCH 0232/1224] #137 added guard clauses installed LiteGuard.Source package into ScriptCs.Core only and linked from other projects created ScriptCs.ruleset based on MS recommended rules and added CA1062: Validate arguments of public methods --- ScriptCs.sln | 1 + build/ScriptCs.ruleset | 68 +++++++++++++ .../ScriptCs.Contracts.csproj | 1 + src/ScriptCs.Core/Guard.cs | 98 +++++++++++++++++++ .../NugetInstallationProvider.cs | 4 + src/ScriptCs.Core/Package/PackageContainer.cs | 2 + src/ScriptCs.Core/PreProcessorUtil.cs | 8 ++ src/ScriptCs.Core/ScriptCs.Core.csproj | 2 + src/ScriptCs.Core/ScriptPackManager.cs | 2 + src/ScriptCs.Core/packages.config | 2 + .../RoslynScriptDebuggerEngine.cs | 2 + .../RoslynScriptEngine.cs | 4 + .../ScriptCs.Engine.Roslyn.csproj | 4 + src/ScriptCs/Command/CommandFactory.cs | 2 + src/ScriptCs/CompositionRoot.cs | 2 + src/ScriptCs/ScriptCs.csproj | 4 + 16 files changed, 206 insertions(+) create mode 100644 build/ScriptCs.ruleset create mode 100644 src/ScriptCs.Core/Guard.cs diff --git a/ScriptCs.sln b/ScriptCs.sln index 24acd26f..79d00af5 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -25,6 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{9659F354 build\Build.proj = build\Build.proj build\Build.tasks = build\Build.tasks build\ScriptCs.Common.props = build\ScriptCs.Common.props + build\ScriptCs.ruleset = build\ScriptCs.ruleset build\ScriptCs.Version.props = build\ScriptCs.Version.props EndProjectSection EndProject diff --git a/build/ScriptCs.ruleset b/build/ScriptCs.ruleset new file mode 100644 index 00000000..ee4724e6 --- /dev/null +++ b/build/ScriptCs.ruleset @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 94e645aa..3f667d25 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -7,6 +7,7 @@ ScriptCs.Contracts ScriptCs.Contracts ..\..\ + ..\..\build\ScriptCs.ruleset diff --git a/src/ScriptCs.Core/Guard.cs b/src/ScriptCs.Core/Guard.cs new file mode 100644 index 00000000..c4076255 --- /dev/null +++ b/src/ScriptCs.Core/Guard.cs @@ -0,0 +1,98 @@ +namespace ScriptCs +{ + using System; + using System.Diagnostics; + using System.Globalization; + + /// + /// Provides guard clauses. + /// + internal static class Guard + { + /// + /// Guards against a null argument. + /// + /// The type of the argument. + /// Name of the parameter. + /// The argument. + /// is null. + /// is restricted to reference types to avoid boxing of value type objects. + [DebuggerStepThrough] + public static void AgainstNullArgument(string parameterName, [ValidatedNotNull]TArgument argument) where TArgument : class + { + if (argument == null) + { + throw new ArgumentNullException(parameterName, string.Format(CultureInfo.InvariantCulture, "{0} is null.", parameterName)); + } + } + + /// + /// Guards against a null argument if can be null. + /// + /// The type of the argument. + /// Name of the parameter. + /// The argument. + /// is null. + /// + /// Performs a type check to avoid boxing of value type objects. + /// + [DebuggerStepThrough] + public static void AgainstNullArgumentIfNullable(string parameterName, [ValidatedNotNull]TArgument argument) + { + if (typeof(TArgument).IsNullableType() && argument == null) + { + throw new ArgumentNullException(parameterName, string.Format(CultureInfo.InvariantCulture, "{0} is null.", parameterName)); + } + } + + /// + /// Guards against a null argument property value. + /// + /// The type of the property. + /// Name of the parameter. + /// Name of the property. + /// The argument property. + /// is null. + /// is restricted to reference types to avoid boxing of value type objects. + [DebuggerStepThrough] + public static void AgainstNullArgumentProperty(string parameterName, string propertyName, [ValidatedNotNull]TProperty argumentProperty) + where TProperty : class + { + if (argumentProperty == null) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "{0}.{1} is null.", parameterName, propertyName), parameterName); + } + } + + /// + /// Guards against a null argument property value if can be null. + /// + /// The type of the property. + /// Name of the parameter. + /// Name of the property. + /// The argument property. + /// is null. + /// + /// Performs a type check to avoid boxing of value type objects. + /// + [DebuggerStepThrough] + public static void AgainstNullArgumentPropertyIfNullable( + string parameterName, string propertyName, [ValidatedNotNull]TProperty argumentProperty) + { + if (typeof(TProperty).IsNullableType() && argumentProperty == null) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "{0}.{1} is null.", parameterName, propertyName), parameterName); + } + } + + private static bool IsNullableType(this Type type) + { + return !type.IsValueType || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + + // NOTE: when applied to a parameter, this attribute provides an indication to code analysis that the argument has been null checked + private sealed class ValidatedNotNullAttribute : Attribute + { + } + } +} diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index 804276a5..44d0c5ac 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -14,6 +14,8 @@ public class NugetInstallationProvider : IInstallationProvider public NugetInstallationProvider(IFileSystem fileSystem) { + Guard.AgainstNullArgument("fileSystem", fileSystem); + _fileSystem = fileSystem; var path = Path.Combine(fileSystem.CurrentDirectory, Constants.PackagesFolder); _repositoryUrls = GetRepositorySources(path); @@ -47,6 +49,8 @@ public IEnumerable GetRepositorySources(string path) public bool InstallPackage(IPackageReference packageId, bool allowPreRelease = false, Action packageInstalled = null) { + Guard.AgainstNullArgument("packageId", packageId); + var useVersion = packageId.Version.CompareTo(new Version()) != 0; try { diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index 6954fbd7..802153af 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -47,6 +47,8 @@ public IEnumerable CreatePackageFile() public IPackageObject FindPackage(string path, IPackageReference packageRef) { + Guard.AgainstNullArgument("packageRef", packageRef); + var repository = new LocalPackageRepository(path); var package = packageRef.Version != null diff --git a/src/ScriptCs.Core/PreProcessorUtil.cs b/src/ScriptCs.Core/PreProcessorUtil.cs index d9ad5016..a155cf05 100644 --- a/src/ScriptCs.Core/PreProcessorUtil.cs +++ b/src/ScriptCs.Core/PreProcessorUtil.cs @@ -13,21 +13,29 @@ public static bool IsNonDirectiveLine(string line) public static bool IsUsingLine(string line) { + Guard.AgainstNullArgument("line", line); + return line.TrimStart(' ').StartsWith(UsingString) && !line.Contains("{") && line.Contains(";"); } public static bool IsRLine(string line) { + Guard.AgainstNullArgument("line", line); + return line.TrimStart(' ').StartsWith(RString); } public static bool IsLoadLine(string line) { + Guard.AgainstNullArgument("line", line); + return line.TrimStart(' ').StartsWith(LoadString); } public static string GetPath(string replaceString, string line) { + Guard.AgainstNullArgument("line", line); + var filepath = line.Trim(' ').Replace(replaceString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); return filepath; } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index adf91081..e6a0aa08 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -7,6 +7,7 @@ ScriptCs ScriptCs.Core ..\..\ + ..\..\build\ScriptCs.ruleset @@ -49,6 +50,7 @@ + diff --git a/src/ScriptCs.Core/ScriptPackManager.cs b/src/ScriptCs.Core/ScriptPackManager.cs index 6f4c6ad9..9015751a 100644 --- a/src/ScriptCs.Core/ScriptPackManager.cs +++ b/src/ScriptCs.Core/ScriptPackManager.cs @@ -10,6 +10,8 @@ public class ScriptPackManager : IScriptPackManager public ScriptPackManager(IEnumerable contexts) { + Guard.AgainstNullArgument("contexts", contexts); + foreach (var context in contexts) { _contexts.Add(context.GetType(), context); diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 9e7aca92..953a2ce5 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -3,5 +3,7 @@ + + \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index 51fdff79..f1043270 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -22,6 +22,8 @@ public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory, ILog log protected override object Execute(string code, Session session) { + Guard.AgainstNullArgument("session", session); + _logger.Debug("Compiling submission"); var submission = session.CompileSubmission(code); var exeBytes = new byte[0]; diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index a3d0b4fd..50036033 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -30,6 +30,8 @@ public string BaseDirectory public object Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { + Guard.AgainstNullArgument("scriptPackSession", scriptPackSession); + _logger.Info("Starting to create execution components"); _logger.Debug("Creating script host"); @@ -82,6 +84,8 @@ public object Execute(string code, IEnumerable references, IEnumerableScriptCs.Engine.Roslyn ScriptCs.Engine.Roslyn ..\..\ + ..\..\build\ScriptCs.ruleset @@ -33,6 +34,9 @@ Properties\CommonVersionInfo.cs + + Guard.cs + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 83e9afc4..644f2256 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -13,6 +13,8 @@ public CommandFactory(ScriptServiceRoot scriptServiceRoot) public ICommand CreateCommand(ScriptCsArgs args) { + Guard.AgainstNullArgument("args", args); + if (args.Help) { return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: true); diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index e327b61d..cb244732 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -20,6 +20,8 @@ public class CompositionRoot public CompositionRoot(ScriptCsArgs args) { + Guard.AgainstNullArgument("args", args); + _debug = args.Debug; _logLevel = args.LogLevel; _shouldInitDrirectoryCatalog = ShouldInitDrirectoryCatalog(args); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index e2249072..47286cee 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -7,6 +7,7 @@ ScriptCs scriptcs ..\..\ + ..\..\build\ScriptCs.ruleset ..\..\common\Icon.ico @@ -57,6 +58,9 @@ Properties\CommonVersionInfo.cs + + Guard.cs + From 1a65856fb7e3aabd8859f9a27eb5aa326bc0b24f Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 13 May 2013 17:41:44 -0300 Subject: [PATCH 0233/1224] Bump the version to v0.5.0-alpha --- build/ScriptCs.Version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 7dae5744..81cd5a30 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -4,12 +4,12 @@ 0 - 4 + 5 0 - + alpha From 3fed85bdb04c15c01580082896d92cf99f3e32ef Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 13 May 2013 17:55:44 -0400 Subject: [PATCH 0234/1224] Respect the allowPreRelease flag even if no version is provided --- .../Package/InstallationProvider/NugetInstallationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index 44d0c5ac..930554b7 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -62,7 +62,7 @@ public bool InstallPackage(IPackageReference packageId, bool allowPreRelease = f } else { - _manager.InstallPackage(packageId.PackageId); + _manager.InstallPackage(packageId.PackageId, null, false, allowPreRelease); } if (packageInstalled != null) From 1fa1b849bcf8cb832fb5a92ab6e35e560b60d63b Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 14 May 2013 10:55:55 +0200 Subject: [PATCH 0235/1224] Refactored FilePreProcessor to remove #r directives and return them in result --- src/ScriptCs.Core/FilePreProcessor.cs | 201 +++++++++++------- src/ScriptCs.Core/FilePreProcessorResult.cs | 22 ++ src/ScriptCs.Core/IFilePreProcessor.cs | 2 +- src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs.Core/ScriptExecutor.cs | 19 +- src/ScriptCs/Repl.cs | 17 +- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 109 ++++------ .../ScriptExecutorTests.cs | 30 +-- test/ScriptCs.Tests/ReplTests.cs | 3 + 9 files changed, 225 insertions(+), 179 deletions(-) create mode 100644 src/ScriptCs.Core/FilePreProcessorResult.cs diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 1a7763d2..54496f35 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -1,5 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Text; + using Common.Logging; namespace ScriptCs @@ -7,8 +11,8 @@ namespace ScriptCs public class FilePreProcessor : IFilePreProcessor { private readonly ILog _logger; - - protected readonly IFileSystem _fileSystem; + + private readonly IFileSystem _fileSystem; public FilePreProcessor(IFileSystem fileSystem, ILog logger) { @@ -16,106 +20,145 @@ public FilePreProcessor(IFileSystem fileSystem, ILog logger) _logger = logger; } - public string ProcessFile(string path) + public FilePreProcessorResult ProcessFile(string path) { - _logger.DebugFormat("{0} - Reading lines", path); - var entryFile = _fileSystem.ReadFileLines(path); - var usings = new List(); - var rs = new List(); - var loads = new List(); - - _logger.DebugFormat("{0} - Parsing ", path); - var parsed = ParseFile(path, entryFile, ref usings, ref rs, ref loads); - - _logger.DebugFormat("{0} - Generating references (#r)", path); - var result = GenerateRs(rs); - if (!string.IsNullOrWhiteSpace(result)) - { - result += _fileSystem.NewLine; - } + var context = new FilePreProcessContext(); - _logger.DebugFormat("{0} - Generating using statements", path); - result += GenerateUsings(usings); - if (!string.IsNullOrWhiteSpace(result)) - { - result += _fileSystem.NewLine; - } + _logger.DebugFormat("Starting pre-processing"); + + ParseFile(path, context); + + var code = GenerateScript(context); - result += parsed; + _logger.DebugFormat("Pre-processing finished successfully"); - return result; + return new FilePreProcessorResult + { + Usings = context.Usings, + LoadedFiles = context.LoadedScripts, + References = context.References, + Code = code + }; } - protected virtual string GenerateUsings(ICollection usingLines) + private static string GenerateScript(FilePreProcessContext context) { - return string.Join(_fileSystem.NewLine, usingLines.Distinct()); + var stringBuilder = new StringBuilder(); + + AppendUsings(stringBuilder, context.Usings); + + stringBuilder.Append(string.Join(Environment.NewLine, context.Body)); + + return stringBuilder.ToString(); } - protected virtual string GenerateRs(ICollection rLines) + private static void AppendUsings(StringBuilder stringBuilder, IEnumerable items) { - return string.Join(_fileSystem.NewLine, rLines.Distinct()); + var lines = items.Distinct().Select(item => string.Format("using {0};", item)).ToList(); + + if (lines.Count == 0) return; + + stringBuilder.AppendLine(string.Join(Environment.NewLine, lines)); + stringBuilder.AppendLine(); // Insert a blank separator line } - private string ParseFile(string path, IEnumerable file, ref List usings, ref List rs, ref List loads) + private void ParseFile(string path, FilePreProcessContext context) { - var fileList = file.ToList(); - var firstCode = fileList.FindIndex(l => PreProcessorUtil.IsNonDirectiveLine(l)); - - var firstBody = fileList.FindIndex(l => PreProcessorUtil.IsNonDirectiveLine(l) && !PreProcessorUtil.IsUsingLine(l)); - - // add #line before the actual code begins - // +1 because we are in a zero indexed list, but line numbers are 1 indexed - // we need to keep the original position of the actual line - if (firstBody != -1) - { - _logger.DebugFormat("Added #line statement for file {0} at line {1}", path, firstBody); - fileList.Insert(firstBody, string.Format(@"#line {0} ""{1}""", firstBody + 1, path)); + _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); + + var fileLines = _fileSystem.ReadFileLines(path).ToList(); + + InsertLineDirective(path, fileLines); + + var codeIndex = fileLines.FindIndex(PreProcessorUtil.IsNonDirectiveLine); + + for (var index = 0; index < fileLines.Count; index++) + { + ProcessLine(context, fileLines[index], index < codeIndex || codeIndex < 0); } - - for (var i = 0; i < fileList.Count; i++) + + context.LoadedScripts.Add(path); + } + + private static void InsertLineDirective(string path, List fileLines) + { + var bodyIndex = fileLines.FindIndex(line => PreProcessorUtil.IsNonDirectiveLine(line) && !PreProcessorUtil.IsUsingLine(line)); + if (bodyIndex == -1) return; + + var directiveLine = string.Format("#line {0} \"{1}\"", bodyIndex + 1, path); + fileLines.Insert(bodyIndex, directiveLine); + } + + private void ProcessLine(FilePreProcessContext context, string line, bool isBeforeCode) + { + if (PreProcessorUtil.IsUsingLine(line)) { - var line = fileList[i]; - if (PreProcessorUtil.IsUsingLine(line)) + var @using = GetUsing(line); + if (!context.Usings.Contains(@using)) { - usings.Add(line); + context.Usings.Add(@using); } - else if (PreProcessorUtil.IsRLine(line)) + + return; + } + + if (PreProcessorUtil.IsRLine(line)) + { + if (isBeforeCode) { - if (i < firstCode) - { - rs.Add(line); - } - else + var reference = GetReference(line); + if (!context.References.Contains(reference)) { - fileList[i] = string.Empty; + context.References.Add(reference); } - } - else if (PreProcessorUtil.IsLoadLine(line)) + } + + return; + } + + if (PreProcessorUtil.IsLoadLine(line)) + { + var filePath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); + + if (isBeforeCode && !context.LoadedScripts.Contains(filePath)) { - if ((i < firstCode || firstCode < 0) && !loads.Contains(line)) - { - var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); - var filecontent = _fileSystem.IsPathRooted(filepath) - ? _fileSystem.ReadFileLines(filepath) - : _fileSystem.ReadFileLines(_fileSystem.CurrentDirectory + @"\" + filepath); - - if (filecontent != null) - { - loads.Add(line); - _logger.DebugFormat("Parsing file {0}", path); - var parsed = ParseFile(filepath, filecontent, ref usings, ref rs, ref loads); - fileList[i] = parsed; - } - } - else - { - fileList[i] = string.Empty; - } + ParseFile(filePath, context); } + + return; } - var result = string.Join(_fileSystem.NewLine, fileList.Where(line => !PreProcessorUtil.IsUsingLine(line) && !PreProcessorUtil.IsRLine(line))); - return result; + // If we've reached this, the line is part of the body... + context.Body.Add(line); + } + + private static string GetUsing(string line) + { + return line.TrimStart(' ').Replace(PreProcessorUtil.UsingString, string.Empty).Replace(";", string.Empty); + } + + private static string GetReference(string line) + { + return line.TrimStart(' ').Replace(PreProcessorUtil.RString, string.Empty).Replace("\"", string.Empty); + } + + private class FilePreProcessContext + { + public FilePreProcessContext() + { + Usings = new List(); + References = new List(); + LoadedScripts = new List(); + Body = new List(); + } + + public List Usings { get; private set; } + + public List References { get; private set; } + + public List LoadedScripts { get; private set; } + + public List Body { get; private set; } } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/FilePreProcessorResult.cs b/src/ScriptCs.Core/FilePreProcessorResult.cs new file mode 100644 index 00000000..7b46f9c9 --- /dev/null +++ b/src/ScriptCs.Core/FilePreProcessorResult.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public class FilePreProcessorResult + { + public FilePreProcessorResult() + { + Usings = new List(); + LoadedFiles = new List(); + References = new List(); + } + + public List Usings { get; set; } + + public List LoadedFiles { get; set; } + + public List References { get; set; } + + public string Code { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/IFilePreProcessor.cs b/src/ScriptCs.Core/IFilePreProcessor.cs index 1929da65..b136cc24 100644 --- a/src/ScriptCs.Core/IFilePreProcessor.cs +++ b/src/ScriptCs.Core/IFilePreProcessor.cs @@ -2,6 +2,6 @@ { public interface IFilePreProcessor { - string ProcessFile(string path); + FilePreProcessorResult ProcessFile(string path); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index e6a0aa08..416e6c8d 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -49,6 +49,7 @@ Properties\CommonVersionInfo.cs + diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index c4a15e4d..e6e675fc 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -8,14 +8,14 @@ namespace ScriptCs { public class ScriptExecutor : IScriptExecutor { - private static readonly string[] DefaultReferences = new[] {"System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq"}; - private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks"}; + private static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; private readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; private readonly IScriptEngine _scriptEngine; private readonly ILog _logger; - + public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) { _fileSystem = fileSystem; @@ -27,23 +27,22 @@ public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) { var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); - - var references = DefaultReferences.Union(paths); _scriptEngine.BaseDirectory = bin; _logger.Debug("Initializing script packs"); var scriptPackSession = new ScriptPackSession(scriptPacks); - + scriptPackSession.InitializePacks(); var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); - - _logger.DebugFormat("File to process: {0}", path); - var code = _filePreProcessor.ProcessFile(path); + + var result = _filePreProcessor.ProcessFile(path); + + var references = DefaultReferences.Union(paths).Union(result.References); _logger.Debug("Starting execution in engine"); - _scriptEngine.Execute(code, references, DefaultNamespaces, scriptPackSession); + _scriptEngine.Execute(result.Code, references, DefaultNamespaces, scriptPackSession); _logger.Debug("Terminating packs"); scriptPackSession.TerminatePacks(); diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 10aa99cf..d360e2ea 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -8,18 +8,18 @@ namespace ScriptCs { - public class Repl + public class Repl { public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; public IFileSystem FileSystem { get; private set; } public IScriptEngine ScriptEngine { get; private set; } - public IFilePreProcessor FilePreProcessor { get; private set; } + public IFilePreProcessor FilePreProcessor { get; private set; } public ILog Logger { get; private set; } - public IConsole Console { get; private set; } + public IConsole Console { get; private set; } public ScriptPackSession ScriptPackSession { get; private set; } - public IEnumerable References { get; private set; } + public IEnumerable References { get; private set; } public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console, IFilePreProcessor filePreProcessor) { @@ -60,7 +60,8 @@ public void Execute(string script) if (PreProcessorUtil.IsLoadLine(script)) { var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, script); - script = FilePreProcessor.ProcessFile(filepath); + var processorResult = FilePreProcessor.ProcessFile(filepath); + script = processorResult.Code; } else if (PreProcessorUtil.IsRLine(script)) { @@ -74,9 +75,7 @@ public void Execute(string script) if (result != null) { Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ToJsv() - - ); + Console.WriteLine(result.ToJsv()); } } catch (Exception ex) @@ -87,4 +86,4 @@ public void Execute(string script) Console.ForegroundColor = foregroundColor; } } -} +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index aad6ca55..52b65e44 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -59,13 +59,13 @@ public ProcessFileMethod() { _fileSystem = new Mock(); _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script1.csx"))) .Returns(_file1.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script2.csx"))) .Returns(_file2.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script3.csx"))) .Returns(_file3.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script4.csx"))) .Returns(_file4.ToArray()); _logger = new Mock(); @@ -75,11 +75,11 @@ public ProcessFileMethod() public void MultipleUsingStatementsShouldProduceDistinctOutput() { var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\script1.csx"); + var result = processor.ProcessFile("script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))), Times.Exactly(3)); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("script"))), Times.Exactly(3)); Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); } @@ -87,9 +87,9 @@ public void MultipleUsingStatementsShouldProduceDistinctOutput() public void UsingStateMentsShoulAllBeAtTheTop() { var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\script1.csx"); + var result = processor.ProcessFile("script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); @@ -100,12 +100,12 @@ public void UsingStateMentsShoulAllBeAtTheTop() public void ShouldNotLoadInlineLoads() { var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - processor.ProcessFile("\\script1.csx"); + processor.ProcessFile("script1.csx"); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script4.csx")), Times.Once()); } [Fact] @@ -120,18 +120,18 @@ public void ShouldNotLoadSameFileTwice() var fs = new Mock(); fs.Setup(i => i.NewLine).Returns(Environment.NewLine); - fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "script2.csx"))) .Returns(file.ToArray()); - fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "script4.csx"))) .Returns(_file4.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - processor.ProcessFile("\\script1.csx"); + processor.ProcessFile("script1.csx"); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script4.csx")), Times.Once()); } [Fact] @@ -145,12 +145,12 @@ public void LoadBeforeUsingShouldBeAllowed() @"Console.WriteLine(""abc"");" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "file.csx"))).Returns(file.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\file.csx"); + var result = processor.ProcessFile("file.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); @@ -167,17 +167,18 @@ public void ShouldNotBeAllowedToLoadAfterUsing() @"Console.WriteLine(""abc"");", @"#load ""script4.csx""" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "file.csx"))).Returns(file.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\file.csx"); + var result = processor.ProcessFile("file.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); Assert.Equal(1, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); // consider #line directive Assert.Equal(4, splitOutput.Length); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script4.csx")), Times.Never()); } [Fact] @@ -194,12 +195,12 @@ public void UsingInCodeDoesNotCountAsUsingImport() @"//do stuff", @"}" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "file.csx"))).Returns(file.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\file.csx"); + var result = processor.ProcessFile("file.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var firstNonImportUsing = splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); @@ -207,33 +208,6 @@ public void UsingInCodeDoesNotCountAsUsingImport() Assert.True(firstNonImportUsing > firstCodeLine); } - [Fact] - public void ShouldHaveReferencesOnTop() - { - var file1 = new List - { - @"#r ""My.dll""", - @"#load ""script2.csx""", - "using System;", - @"Console.WriteLine(""Hi!"");" - }; - - var fs = new Mock(); - fs.Setup(i => i.NewLine).Returns(Environment.NewLine); - fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))).Returns(file1.ToArray()); - fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))).Returns(_file2.ToArray()); - - var processor = new FilePreProcessor(fs.Object, _logger.Object); - var output = processor.ProcessFile("\\script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None).ToList(); - - var lastR = splitOutput.FindLastIndex(line => line.StartsWith("#r ")); - var firstNotR = splitOutput.FindIndex(line => !line.StartsWith("#r ")); - - lastR.ShouldNotEqual(-1); - Assert.True(lastR < firstNotR); - } - [Fact] public void ShouldHaveReferencesFromAllFiles() { @@ -252,16 +226,15 @@ public void ShouldHaveReferencesFromAllFiles() @"Console.WriteLine(""Hi!"");" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script1.csx"))) .Returns(file1.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\scriptX.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "scriptX.csx"))) .Returns(file2.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\script1.csx"); + var result = processor.ProcessFile("script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); - splitOutput.Count(line => line.StartsWith("#r ")).ShouldEqual(2); + result.References.Count.ShouldEqual(2); } [Fact] @@ -321,15 +294,17 @@ public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() var preProcessor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var file = preProcessor.ProcessFile(@"C:\f1.csx"); - - var fileLines = file.Split(new[]{ Environment.NewLine }, StringSplitOptions.None); + var result = preProcessor.ProcessFile(@"C:\f1.csx"); + + var fileLines = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); // using statements go first, after that f4 -> f5 -> f2 -> f3 -> f1 var line = 0; fileLines[line++].ShouldEqual("using System;"); fileLines[line++].ShouldEqual("using System.Diagnostics;"); + line++; // Skip blank separator line between usings and body... + fileLines[line++].ShouldEqual(@"#line 1 ""C:\f4.csx"""); fileLines[line++].ShouldEqual(f4[0]); @@ -347,4 +322,4 @@ public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() } } } -} +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index e303c23d..19bd6806 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -46,7 +46,7 @@ public void ConstructsAbsolutePathBeforePreProcessingFile() fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); @@ -62,7 +62,7 @@ public void DoNotChangePathIfAbsolute() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); @@ -76,6 +76,8 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() // arrange var scriptEngine = new Mock(); var fileSystem = new Mock(); + var preProcessor = new Mock(); + preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); @@ -83,7 +85,7 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() scriptEngine.SetupProperty(e => e.BaseDirectory); - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); + var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); var scriptName = "script.csx"; var paths = new string[0]; @@ -120,7 +122,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut var paths = new string[0]; var recipes = Enumerable.Empty(); - preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(code).Verifiable(); + preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(new FilePreProcessorResult { Code = code }).Verifiable(); scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny())); // act @@ -130,18 +132,20 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); - + } [Fact] public void ShouldAddReferenceToEachDestinationFile() { // arrange - var defaultReferences = new[] {"System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq"}; + var defaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; var fileSystem = new Mock(); var scriptEngine = new Mock(); + var preProcessor = new Mock(); + preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); + var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); var currentDirectory = @"C:\"; var destinationFilePath1 = Path.Combine(currentDirectory, @"bin\fileName1.cs"); @@ -175,7 +179,7 @@ public void ShouldInitializeScriptPacks() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); @@ -196,7 +200,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); @@ -213,18 +217,18 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() [Fact] public void ExecutorShouldPassDefaultNamespacesToEngine() { - var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks"}; + var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var engine = new Mock(); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine:engine); + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); @@ -241,7 +245,7 @@ public void ExecutorShouldPassDefaultReferencesToEngine() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var engine = new Mock(); diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 248040dd..5f5dd495 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -175,6 +175,9 @@ public void ShouldProcessFileIfLineIsALoad() public void ShouldExecuteLoadedFileIfLineIsALoad() { var mocks = new Mocks(); + mocks.FilePreProcessor.Setup(x => x.ProcessFile(It.IsAny())) + .Returns(new FilePreProcessorResult()); + _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); From 3e72bd8d996cd5fc1615833ee174499869d5d65f Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 15 May 2013 16:57:25 +0200 Subject: [PATCH 0236/1224] Replaced methods with PreProcessorUtil methods. Added tests --- src/ScriptCs.Core/FilePreProcessor.cs | 26 +++--- src/ScriptCs.Core/FilePreProcessorResult.cs | 4 +- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 79 +++++++++++++++++++ 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 54496f35..db03bacd 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -35,7 +35,7 @@ public FilePreProcessorResult ProcessFile(string path) return new FilePreProcessorResult { Usings = context.Usings, - LoadedFiles = context.LoadedScripts, + LoadedScripts = context.LoadedScripts, References = context.References, Code = code }; @@ -93,7 +93,7 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo { if (PreProcessorUtil.IsUsingLine(line)) { - var @using = GetUsing(line); + var @using = PreProcessorUtil.GetPath(PreProcessorUtil.UsingString, line); if (!context.Usings.Contains(@using)) { context.Usings.Add(@using); @@ -106,7 +106,7 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo { if (isBeforeCode) { - var reference = GetReference(line); + var reference = PreProcessorUtil.GetPath(PreProcessorUtil.RString, line); if (!context.References.Contains(reference)) { context.References.Add(reference); @@ -118,11 +118,13 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo if (PreProcessorUtil.IsLoadLine(line)) { - var filePath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); - - if (isBeforeCode && !context.LoadedScripts.Contains(filePath)) + if (isBeforeCode) { - ParseFile(filePath, context); + var filePath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); + if (!context.LoadedScripts.Contains(filePath)) + { + ParseFile(filePath, context); + } } return; @@ -132,16 +134,6 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo context.Body.Add(line); } - private static string GetUsing(string line) - { - return line.TrimStart(' ').Replace(PreProcessorUtil.UsingString, string.Empty).Replace(";", string.Empty); - } - - private static string GetReference(string line) - { - return line.TrimStart(' ').Replace(PreProcessorUtil.RString, string.Empty).Replace("\"", string.Empty); - } - private class FilePreProcessContext { public FilePreProcessContext() diff --git a/src/ScriptCs.Core/FilePreProcessorResult.cs b/src/ScriptCs.Core/FilePreProcessorResult.cs index 7b46f9c9..94c27ee9 100644 --- a/src/ScriptCs.Core/FilePreProcessorResult.cs +++ b/src/ScriptCs.Core/FilePreProcessorResult.cs @@ -7,13 +7,13 @@ public class FilePreProcessorResult public FilePreProcessorResult() { Usings = new List(); - LoadedFiles = new List(); + LoadedScripts = new List(); References = new List(); } public List Usings { get; set; } - public List LoadedFiles { get; set; } + public List LoadedScripts { get; set; } public List References { get; set; } diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index 52b65e44..3fdd1d68 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -108,6 +108,85 @@ public void ShouldNotLoadInlineLoads() _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script4.csx")), Times.Once()); } + [Fact] + public void ShouldReturnResultWithAllLoadedFiles() + { + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); + var result = processor.ProcessFile("script1.csx"); + + result.LoadedScripts.Count.ShouldEqual(3); + result.LoadedScripts.ShouldContain("script1.csx"); + result.LoadedScripts.ShouldContain("script2.csx"); + result.LoadedScripts.ShouldContain("script4.csx"); + } + + [Fact] + public void ShouldReturnResultWithAllUsings() + { + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); + var result = processor.ProcessFile("script1.csx"); + + result.Usings.Count.ShouldEqual(2); + result.Usings.ShouldContain("System"); + result.Usings.ShouldContain("System.Core"); + } + + [Fact] + public void ShouldReturnResultWithAllReferences() + { + var file1 = new List + { + @"#r ""My.dll""", + @"#load ""scriptX.csx""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + var file2 = new List + { + @"#r ""My2.dll""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script1.csx"))).Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "scriptX.csx"))).Returns(file2.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); + var result = processor.ProcessFile("script1.csx"); + + result.References.Count.ShouldEqual(2); + result.References.ShouldContain("My.dll"); + result.References.ShouldContain("My2.dll"); + } + + [Fact] + public void ShouldNotIncludeReferencesInCode() + { + var file1 = new List + { + @"#r ""My.dll""", + @"#load ""scriptX.csx""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + var file2 = new List + { + @"#r ""My2.dll""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script1.csx"))).Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "scriptX.csx"))).Returns(file2.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); + var result = processor.ProcessFile("script1.csx"); + + result.Code.ShouldNotContain("#r"); + } + [Fact] public void ShouldNotLoadSameFileTwice() { From 542844a14c493c510339a3bf195597bd47d1dfe2 Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Wed, 15 May 2013 18:30:08 +0200 Subject: [PATCH 0237/1224] Console colors are now properly reset when exiting the REPL. --- src/ScriptCs/IConsole.cs | 2 ++ src/ScriptCs/Repl.cs | 17 ++++++++-------- src/ScriptCs/ReplConsole.cs | 21 ++++++++++++++++++++ test/ScriptCs.Tests/ReplTests.cs | 34 +++++++++++++++++++------------- 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/ScriptCs/IConsole.cs b/src/ScriptCs/IConsole.cs index cde0a8b5..f7935d91 100644 --- a/src/ScriptCs/IConsole.cs +++ b/src/ScriptCs/IConsole.cs @@ -11,6 +11,8 @@ public interface IConsole void Write(string value); void WriteLine(string value); string ReadLine(); + void Exit(); + void ResetColor(); ConsoleColor ForegroundColor { get; set; } } } diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 10aa99cf..57dfc47b 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -8,18 +8,18 @@ namespace ScriptCs { - public class Repl + public class Repl { public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; public IFileSystem FileSystem { get; private set; } public IScriptEngine ScriptEngine { get; private set; } - public IFilePreProcessor FilePreProcessor { get; private set; } + public IFilePreProcessor FilePreProcessor { get; private set; } public ILog Logger { get; private set; } - public IConsole Console { get; private set; } + public IConsole Console { get; private set; } public ScriptPackSession ScriptPackSession { get; private set; } - public IEnumerable References { get; private set; } + public IEnumerable References { get; private set; } public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console, IFilePreProcessor filePreProcessor) { @@ -53,8 +53,6 @@ public void Terminate() public void Execute(string script) { - var foregroundColor = Console.ForegroundColor; - try { if (PreProcessorUtil.IsLoadLine(script)) @@ -75,7 +73,7 @@ public void Execute(string script) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(result.ToJsv() - + ); } } @@ -84,7 +82,10 @@ public void Execute(string script) Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + ex + "\r\n"); } - Console.ForegroundColor = foregroundColor; + finally + { + Console.ResetColor(); + } } } } diff --git a/src/ScriptCs/ReplConsole.cs b/src/ScriptCs/ReplConsole.cs index 6100ce2b..a2eddbcb 100644 --- a/src/ScriptCs/ReplConsole.cs +++ b/src/ScriptCs/ReplConsole.cs @@ -4,6 +4,11 @@ namespace ScriptCs { public class ReplConsole : IConsole { + public ReplConsole() + { + Console.CancelKeyPress += HandleCancelKeyPress; + } + public void Write(string value) { Console.Write(value); @@ -19,6 +24,22 @@ public string ReadLine() return Console.ReadLine(); } + public void Exit() + { + ResetColor(); + Console.CancelKeyPress -= HandleCancelKeyPress; + } + + public void ResetColor() + { + Console.ResetColor(); + } + + private void HandleCancelKeyPress(object sender, ConsoleCancelEventArgs e) + { + ResetColor(); + } + public ConsoleColor ForegroundColor { get { return Console.ForegroundColor; } diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 248040dd..d434ee39 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -56,15 +56,15 @@ public class TheInitializeMethod { private Mocks _mocks; private Repl _repl; - + public TheInitializeMethod() { _mocks = new Mocks(); _repl = GetRepl(_mocks); _mocks.FileSystem.Setup(x => x.CurrentDirectory).Returns(@"c:\"); - var paths = new []{@"c:\path"}; - _repl.Initialize(paths, new[] {_mocks.ScriptPack.Object}); - } + var paths = new[] { @"c:\path" }; + _repl.Initialize(paths, new[] { _mocks.ScriptPack.Object }); + } [Fact] public void PopulatesReferences() @@ -79,7 +79,7 @@ public void PopulatesReferences() [Fact] public void SetsTheScriptEngineBaseDirectory() { - _mocks.ScriptEngine.VerifySet(x=>x.BaseDirectory = @"c:\bin"); + _mocks.ScriptEngine.VerifySet(x => x.BaseDirectory = @"c:\bin"); } [Fact] @@ -91,7 +91,7 @@ public void CreatesTheScriptPackSession() [Fact] public void InitializesScriptPacks() { - _mocks.ScriptPack.Verify(x=>x.Initialize(It.IsAny())); + _mocks.ScriptPack.Verify(x => x.Initialize(It.IsAny())); } } @@ -99,13 +99,13 @@ public class TheTerminateMethod { private Mocks _mocks; private Repl _repl; - + public TheTerminateMethod() { _mocks = new Mocks(); _repl = GetRepl(_mocks); _mocks.FileSystem.Setup(x => x.CurrentDirectory).Returns(@"c:\"); - _repl.Initialize(new List(), new[] {_mocks.ScriptPack.Object}); + _repl.Initialize(new List(), new[] { _mocks.ScriptPack.Object }); _repl.Terminate(); } @@ -120,7 +120,7 @@ public class TheExecuteMethod { private Mocks _mocks; private Repl _repl; - + public TheExecuteMethod() { _mocks = new Mocks(); @@ -132,13 +132,19 @@ public TheExecuteMethod() [Fact] public void SetsTheForegroundColorToCyan() { - _mocks.Console.VerifySet(x=>x.ForegroundColor = ConsoleColor.Cyan, Times.Once()); + _mocks.Console.VerifySet(x => x.ForegroundColor = ConsoleColor.Cyan, Times.Once()); + } + + [Fact] + public void ResetsColorAfterExecutingScript() + { + _mocks.Console.Verify(x => x.ResetColor()); } [Fact] public void CallsExecuteOnTheScriptEngine() { - _mocks.ScriptEngine.Verify(x=>x.Execute("foo", _repl.References, Repl.DefaultNamespaces, It.IsAny())); + _mocks.ScriptEngine.Verify(x => x.Execute("foo", _repl.References, Repl.DefaultNamespaces, It.IsAny())); } [Fact] @@ -154,11 +160,11 @@ public void CatchesExceptionsAndWritesThemInRed() _mocks.Console.Verify(x => x.WriteLine(It.IsAny())); } - + [Fact] public void SetsTheForegroundColorBackToTheDefault() { - _mocks.Console.VerifySet(x=>x.ForegroundColor = ConsoleColor.White); + _mocks.Console.VerifySet(x => x.ForegroundColor = ConsoleColor.White); } [Fact] @@ -167,7 +173,7 @@ public void ShouldProcessFileIfLineIsALoad() var mocks = new Mocks(); _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); - + mocks.FilePreProcessor.Verify(i => i.ProcessFile(It.Is(x => x == "file.csx")), Times.Once()); } From 9de9fe1986a837a1ea8c2783281c97031d478623 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 15 May 2013 14:16:20 -0400 Subject: [PATCH 0238/1224] ExecuteReplCommand should use the implementation of IConsole provided to the ctor --- src/ScriptCs/Command/ExecuteReplCommand.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 13cd792b..1d275620 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -37,7 +37,7 @@ IConsole console public CommandResult Execute() { - Console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); + _console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console, _filePreProcessor); repl.Initialize(GetAssemblyPaths(_fileSystem.CurrentDirectory), _scriptPackResolver.GetPacks()); try @@ -57,8 +57,8 @@ public CommandResult Execute() private bool ExecuteLine(Repl repl) { - Console.Write("> "); - var line = Console.ReadLine(); + _console.Write("> "); + var line = _console.ReadLine(); if (line == "") return false; From 2cdc371871e4607311c8d73d132a9b6790927945 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 15 May 2013 14:18:44 -0400 Subject: [PATCH 0239/1224] Add test for ExecuteReplCommand.Execute --- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 84 +++++++++++++++++++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 + 2 files changed, 85 insertions(+) create mode 100644 test/ScriptCs.Tests/ExecuteReplCommandTests.cs diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs new file mode 100644 index 00000000..aca52296 --- /dev/null +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Text; +using Common.Logging; +using Moq; +using ScriptCs.Command; +using ScriptCs.Package; +using Xunit; + +namespace ScriptCs.Tests +{ + public class ExecuteReplCommandTests + { + public class TheExecuteMethod + { + [Fact] + public void ShouldPromptForInput() + { + var mockFileSystem = new Mock(); + mockFileSystem.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + + var builder = new StringBuilder(); + + var reader = new StringReader(Environment.NewLine); + var writer = new StringWriter(builder); + + var console = new FakeConsole(writer, reader); + + var root = new ScriptServiceRoot( + mockFileSystem.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + console); + + var commandFactory = new CommandFactory(root); + + var target = commandFactory.CreateCommand(new ScriptCsArgs { Repl = true }); + + target.Execute(); + + Assert.True(builder.ToString().EndsWith("> ")); + Assert.Equal(1, console.ReadLineCounter); + } + } + + public class FakeConsole : IConsole + { + private readonly TextWriter writer; + private readonly TextReader reader; + + public FakeConsole(TextWriter textWriter, TextReader textReader) + { + writer = textWriter; + reader = textReader; + ReadLineCounter = 0; + } + + public ConsoleColor ForegroundColor { get; set; } + + public int ReadLineCounter { get; set; } + + public void Write(string value) + { + writer.Write(value); + } + + public void WriteLine(string value) + { + writer.WriteLine(value); + } + + public string ReadLine() + { + ReadLineCounter++; + return reader.ReadLine(); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index a7d14f0b..6b87c8ea 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -42,6 +42,7 @@ + From 4ad28cc680d3bc19c3e78ed9937db2ec0ff9aeea Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 15 May 2013 20:53:46 +0200 Subject: [PATCH 0240/1224] Added check for existing assembly/script in REPL. Fixes #264 --- src/ScriptCs/Repl.cs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 10aa99cf..bccd5512 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -60,12 +60,27 @@ public void Execute(string script) if (PreProcessorUtil.IsLoadLine(script)) { var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, script); - script = FilePreProcessor.ProcessFile(filepath); + if (FileSystem.FileExists(filepath)) + { + script = FilePreProcessor.ProcessFile(filepath); + } + else + { + throw new FileNotFoundException(string.Format("Could not find script '{0}'", filepath), filepath); + } } else if (PreProcessorUtil.IsRLine(script)) { var assemblyPath = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); - References = References.Union(new[] { assemblyPath }); + if (FileSystem.FileExists(assemblyPath)) + { + References = References.Union(new[] { assemblyPath }); + } + else + { + throw new FileNotFoundException(string.Format("Could not find assembly '{0}'", assemblyPath), assemblyPath); + } + return; } @@ -74,9 +89,7 @@ public void Execute(string script) if (result != null) { Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ToJsv() - - ); + Console.WriteLine(result.ToJsv()); } } catch (Exception ex) From d818a21433d8252b0a0d68765ffbaa93e2b4171c Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 15 May 2013 21:13:32 +0200 Subject: [PATCH 0241/1224] Fixed failing tests and added two more --- test/ScriptCs.Tests/ReplTests.cs | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 248040dd..9e952683 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -165,6 +165,8 @@ public void SetsTheForegroundColorBackToTheDefault() public void ShouldProcessFileIfLineIsALoad() { var mocks = new Mocks(); + mocks.FileSystem.Setup(x => x.FileExists("file.csx")).Returns(true); + _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); @@ -175,17 +177,33 @@ public void ShouldProcessFileIfLineIsALoad() public void ShouldExecuteLoadedFileIfLineIsALoad() { var mocks = new Mocks(); + mocks.FileSystem.Setup(x => x.FileExists("file.csx")).Returns(true); + _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); } + [Fact] + public void ShouldNotExecuteLoadedFileIfFileDoesNotExist() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(x => x.FileExists("file.csx")).Returns(false); + + _repl = GetRepl(mocks); + _repl.Execute("#load \"file.csx\""); + + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); + } + [Fact] public void ShouldReferenceAssemblyIfLineIsAReference() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(x => x.FileExists("my.dll")).Returns(true); + _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); _repl.Execute("#r \"my.dll\""); @@ -194,6 +212,21 @@ public void ShouldReferenceAssemblyIfLineIsAReference() _repl.References.Count().ShouldEqual(7); } + [Fact] + public void ShouldNotReferenceAssemblyIfFileDoesNotExist() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(x => x.FileExists("my.dll")).Returns(false); + + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"my.dll\""); + + //default references = 6 + _repl.References.Count().ShouldEqual(6); + } + [Fact] public void ShouldNotExecuteAnythingIfLineIsAReference() { From 5130901d51ea30a39d712b1dc25db6ad41cfc1f0 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 13 May 2013 21:05:00 +1000 Subject: [PATCH 0242/1224] Adding a filter for non-managed assemblies --- .../RoslynScriptEngine.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 50036033..ab65ce38 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -4,6 +4,7 @@ using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; +using System.IO; namespace ScriptCs.Engine.Roslyn { @@ -35,7 +36,7 @@ public object Execute(string code, IEnumerable references, IEnumerable sessionState; if (!scriptPackSession.State.ContainsKey(SessionKey)) @@ -88,5 +89,20 @@ protected virtual object Execute(string code, Session session) return session.Execute(code); } + + protected bool IsManagedAssembly(string path) + { + if (!File.Exists(path)) return true; + + try + { + AssemblyName.GetAssemblyName(path); + } + catch (System.BadImageFormatException) + { + return false; + } + return true; + } } } \ No newline at end of file From fb78be84e5486765d84170fbaf481b3e4ac21b6e Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 14 May 2013 10:42:44 +1000 Subject: [PATCH 0243/1224] Moving non-managed file detection into the IScriptCommand implementations --- .../RoslynScriptEngine.cs | 18 +----------------- src/ScriptCs/Command/ExecuteReplCommand.cs | 15 +++++++++++++++ src/ScriptCs/Command/ExecuteScriptCommand.cs | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ab65ce38..50036033 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -4,7 +4,6 @@ using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; -using System.IO; namespace ScriptCs.Engine.Roslyn { @@ -36,7 +35,7 @@ public object Execute(string code, IEnumerable references, IEnumerable sessionState; if (!scriptPackSession.State.ContainsKey(SessionKey)) @@ -89,20 +88,5 @@ protected virtual object Execute(string code, Session session) return session.Execute(code); } - - protected bool IsManagedAssembly(string path) - { - if (!File.Exists(path)) return true; - - try - { - AssemblyName.GetAssemblyName(path); - } - catch (System.BadImageFormatException) - { - return false; - } - return true; - } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 1d275620..7ace69db 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Common.Logging; +using System.Reflection; namespace ScriptCs.Command { @@ -77,6 +78,7 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) + .Where(IsManagedAssembly) .ToList(); foreach (var path in assemblyPaths.Select(Path.GetFileName)) @@ -86,5 +88,18 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) return assemblyPaths; } + + private bool IsManagedAssembly(string path) + { + try + { + AssemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return false; + } + return true; + } } } diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index ad217103..a94bc287 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using Common.Logging; +using System.Reflection; namespace ScriptCs.Command { @@ -60,6 +61,7 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) + .Where(IsManagedAssembly) .ToList(); foreach (var path in assemblyPaths.Select(Path.GetFileName)) @@ -69,5 +71,18 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) return assemblyPaths; } + + private bool IsManagedAssembly(string path) + { + try + { + AssemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return false; + } + return true; + } } } \ No newline at end of file From 1423f12f026b01aad3379dc62ae4f57c8b4b0c5b Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 12:27:55 +1000 Subject: [PATCH 0244/1224] Adding abstraction on the AssemblyName API --- src/ScriptCs.Core/IAssemblyName.cs | 13 +++++++++++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs/Command/CommandFactory.cs | 6 ++++-- src/ScriptCs/Command/ExecuteReplCommand.cs | 7 +++++-- src/ScriptCs/Command/ExecuteScriptCommand.cs | 7 +++++-- src/ScriptCs/ScriptServiceRoot.cs | 3 +++ test/ScriptCs.Tests/CleanCommandTests.cs | 16 ++++++++++++---- test/ScriptCs.Tests/CommandFactoryTests.cs | 3 ++- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 7 +++++-- test/ScriptCs.Tests/InstallCommandTests.cs | 7 +++++-- test/ScriptCs.Tests/RestoreCommandTests.cs | 11 ++++++++--- test/ScriptCs.Tests/VersionCommandTests.cs | 4 +++- 12 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 src/ScriptCs.Core/IAssemblyName.cs diff --git a/src/ScriptCs.Core/IAssemblyName.cs b/src/ScriptCs.Core/IAssemblyName.cs new file mode 100644 index 00000000..1ac11d4d --- /dev/null +++ b/src/ScriptCs.Core/IAssemblyName.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs +{ + public interface IAssemblyName + { + string GetAssemblyName(string path); + } +} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index e6a0aa08..7d4a9152 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -51,6 +51,7 @@ + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 644f2256..d23cb199 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -24,7 +24,8 @@ public ICommand CreateCommand(ScriptCsArgs args) { var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console); + _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, + _scriptServiceRoot.AssemblyName); return replCommand; } @@ -35,7 +36,8 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Logger); + _scriptServiceRoot.Logger, + _scriptServiceRoot.AssemblyName); if (args.Restore) { diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 7ace69db..e62f767e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,6 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; private readonly IConsole _console; @@ -25,7 +26,8 @@ public ExecuteReplCommand( IScriptEngine scriptEngine, IFilePreProcessor filePreProcessor, ILog logger, - IConsole console + IConsole console, + IAssemblyName assemblyName ) { _fileSystem = fileSystem; @@ -34,6 +36,7 @@ IConsole console _filePreProcessor = filePreProcessor; _logger = logger; _console = console; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -93,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - AssemblyName.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index a94bc287..79155a19 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,6 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; @@ -20,13 +21,15 @@ public ExecuteScriptCommand(string script, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, - ILog logger) + ILog logger, + IAssemblyName assemblyName) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -76,7 +79,7 @@ private bool IsManagedAssembly(string path) { try { - AssemblyName.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index 40a83c99..ea00605a 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,6 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, + IAssemblyName assemblyName, IConsole console = null) { FileSystem = fileSystem; @@ -25,6 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; + AssemblyName = assemblyName; } public IFileSystem FileSystem { get; private set; } @@ -36,5 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } + public IAssemblyName AssemblyName { get; private set; } } } \ No newline at end of file diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 55e4b4ce..bbef0c4b 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,7 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -50,7 +52,9 @@ public void ShouldDeleteBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -76,7 +80,9 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -103,7 +109,9 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 961ea056..deb8f88a 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,8 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 42d197ce..61c50a1e 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -31,7 +31,9 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -61,7 +63,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index e58dace8..0e4ed500 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,7 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -70,7 +71,9 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index 947f11e7..b84aad8a 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,7 +25,9 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + const string CurrentDirectory = @"C:\"; @@ -65,7 +67,9 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + const string CurrentDirectory = @"C:\"; @@ -105,7 +109,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 29fb50e1..a0623df9 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,7 +42,9 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var factory = new CommandFactory(root); var result = factory.CreateCommand(args); From 7f4a5538a496e189e4952c611119eb8535eef4f4 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 13:36:01 +1000 Subject: [PATCH 0245/1224] Refactoring IAssemblyName to IAssembly Adding implementation for IAssembly interface and adding it to IoC --- src/ScriptCs.Core/Assembly.cs | 11 +++++++++++ src/ScriptCs.Core/IAssemblyName.cs | 11 +++-------- src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs/Command/CommandFactory.cs | 4 ++-- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 ++++---- src/ScriptCs/Command/ExecuteScriptCommand.cs | 8 ++++---- src/ScriptCs/CompositionRoot.cs | 3 ++- src/ScriptCs/ScriptServiceRoot.cs | 6 +++--- test/ScriptCs.Tests/CleanCommandTests.cs | 16 ++++++++-------- test/ScriptCs.Tests/CommandFactoryTests.cs | 4 ++-- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/InstallCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/RestoreCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/VersionCommandTests.cs | 4 ++-- 14 files changed, 56 insertions(+), 48 deletions(-) create mode 100644 src/ScriptCs.Core/Assembly.cs diff --git a/src/ScriptCs.Core/Assembly.cs b/src/ScriptCs.Core/Assembly.cs new file mode 100644 index 00000000..a2b1ec6a --- /dev/null +++ b/src/ScriptCs.Core/Assembly.cs @@ -0,0 +1,11 @@ +using System.Reflection; +namespace ScriptCs +{ + public class Assembly : IAssembly + { + public AssemblyName GetAssemblyName(string path) + { + return AssemblyName.GetAssemblyName(path); + } + } +} diff --git a/src/ScriptCs.Core/IAssemblyName.cs b/src/ScriptCs.Core/IAssemblyName.cs index 1ac11d4d..e4416371 100644 --- a/src/ScriptCs.Core/IAssemblyName.cs +++ b/src/ScriptCs.Core/IAssemblyName.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - +using System.Reflection; namespace ScriptCs { - public interface IAssemblyName + public interface IAssembly { - string GetAssemblyName(string path); + AssemblyName GetAssemblyName(string path); } } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 7d4a9152..494498f7 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -39,6 +39,7 @@ + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d23cb199..080cce7c 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -25,7 +25,7 @@ public ICommand CreateCommand(ScriptCsArgs args) var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, - _scriptServiceRoot.AssemblyName); + _scriptServiceRoot.Assembly); return replCommand; } @@ -37,7 +37,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, _scriptServiceRoot.Logger, - _scriptServiceRoot.AssemblyName); + _scriptServiceRoot.Assembly); if (args.Restore) { diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index e62f767e..bccaff98 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,7 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssemblyName _assemblyName; + private readonly IAssembly _assembly; private readonly ILog _logger; private readonly IConsole _console; @@ -27,7 +27,7 @@ public ExecuteReplCommand( IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssemblyName assemblyName + IAssembly assembly ) { _fileSystem = fileSystem; @@ -36,7 +36,7 @@ IAssemblyName assemblyName _filePreProcessor = filePreProcessor; _logger = logger; _console = console; - _assemblyName = assemblyName; + _assembly = assembly; } public CommandResult Execute() @@ -96,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - _assemblyName.GetAssemblyName(path); + _assembly.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 79155a19..e19c026b 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,7 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssemblyName _assemblyName; + private readonly IAssembly _assembly; private readonly ILog _logger; @@ -22,14 +22,14 @@ public ExecuteScriptCommand(string script, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, ILog logger, - IAssemblyName assemblyName) + IAssembly assembly) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; - _assemblyName = assemblyName; + _assembly = assembly; } public CommandResult Execute() @@ -79,7 +79,7 @@ private bool IsManagedAssembly(string path) { try { - _assemblyName.GetAssemblyName(path); + _assembly.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index cb244732..9ffea091 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -47,7 +47,8 @@ public void Initialize() typeof (ScriptPackResolver), typeof (NugetInstallationProvider), typeof (PackageInstaller), - typeof (ReplConsole) + typeof (ReplConsole), + typeof (Assembly) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index ea00605a..11b885b7 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,7 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssemblyName assemblyName, + IAssembly assembly, IConsole console = null) { FileSystem = fileSystem; @@ -26,7 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - AssemblyName = assemblyName; + Assembly = assembly; } public IFileSystem FileSystem { get; private set; } @@ -38,6 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssemblyName AssemblyName { get; private set; } + public IAssembly Assembly { get; private set; } } } \ No newline at end of file diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index bbef0c4b..9db9f49b 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,9 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -52,8 +52,8 @@ public void ShouldDeleteBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -80,8 +80,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); @@ -109,8 +109,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index deb8f88a..fa1444f9 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,9 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 61c50a1e..07eeffd6 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -31,8 +31,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); @@ -63,8 +63,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 0e4ed500..e077bed9 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,8 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -71,8 +71,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index b84aad8a..7aa7f6db 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,8 +25,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; @@ -67,8 +67,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; @@ -109,8 +109,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index a0623df9..a5a357ea 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,8 +42,8 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); From 8a3b94fc4d1e8f7c3df84623eafd1d23fc8d9a6e Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 13:47:22 +1000 Subject: [PATCH 0246/1224] Implementing a unit test for non-managed assemblies --- .../ExecuteScriptCommandTests.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 07eeffd6..173c5a2f 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -6,6 +6,8 @@ using ScriptCs.Contracts; using ScriptCs.Package; using Xunit; +using System; +using System.Linq; namespace ScriptCs.Tests { @@ -73,6 +75,45 @@ public void ShouldCreateMissingBinFolder() fs.Verify(x => x.CreateDirectory(binFolder), Times.Once()); } + + [Fact] + public void NonManagedAssembliesAreExcluded() + { + const string nonManaged = "non-managed.dll"; + + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + var fs = new Mock(); + fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { + "managed.dll", + nonManaged + }); + + var resolver = new Mock(); + var executor = new Mock(); + var engine = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var logger = new Mock(); + var filePreProcessor = new Mock(); + var assembly = new Mock(); + assembly.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); + + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + executor.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); + } } } } \ No newline at end of file From 53f1468a078196f13e50eee8a844432ef4d4a4bf Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 13 May 2013 21:05:00 +1000 Subject: [PATCH 0247/1224] Adding a filter for non-managed assemblies --- .../RoslynScriptEngine.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 50036033..ab65ce38 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -4,6 +4,7 @@ using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; +using System.IO; namespace ScriptCs.Engine.Roslyn { @@ -35,7 +36,7 @@ public object Execute(string code, IEnumerable references, IEnumerable sessionState; if (!scriptPackSession.State.ContainsKey(SessionKey)) @@ -88,5 +89,20 @@ protected virtual object Execute(string code, Session session) return session.Execute(code); } + + protected bool IsManagedAssembly(string path) + { + if (!File.Exists(path)) return true; + + try + { + AssemblyName.GetAssemblyName(path); + } + catch (System.BadImageFormatException) + { + return false; + } + return true; + } } } \ No newline at end of file From 2e872bfd45fbb3da0f58eee1d95f79c4ac7e3908 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 14 May 2013 10:42:44 +1000 Subject: [PATCH 0248/1224] Moving non-managed file detection into the IScriptCommand implementations --- .../RoslynScriptEngine.cs | 18 +----------------- src/ScriptCs/Command/ExecuteScriptCommand.cs | 2 +- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ab65ce38..50036033 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -4,7 +4,6 @@ using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; -using System.IO; namespace ScriptCs.Engine.Roslyn { @@ -36,7 +35,7 @@ public object Execute(string code, IEnumerable references, IEnumerable sessionState; if (!scriptPackSession.State.ContainsKey(SessionKey)) @@ -89,20 +88,5 @@ protected virtual object Execute(string code, Session session) return session.Execute(code); } - - protected bool IsManagedAssembly(string path) - { - if (!File.Exists(path)) return true; - - try - { - AssemblyName.GetAssemblyName(path); - } - catch (System.BadImageFormatException) - { - return false; - } - return true; - } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index e19c026b..acfb7b28 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -88,4 +88,4 @@ private bool IsManagedAssembly(string path) return true; } } -} \ No newline at end of file +} From 8f8ff161acad85c0f5ba383f31e9599cbf7f13be Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 12:27:55 +1000 Subject: [PATCH 0249/1224] Adding abstraction on the AssemblyName API --- src/ScriptCs/Command/CommandFactory.cs | 3 +-- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 +++---- src/ScriptCs/Command/ExecuteScriptCommand.cs | 7 +++---- src/ScriptCs/ScriptServiceRoot.cs | 8 +++---- test/ScriptCs.Tests/CleanCommandTests.cs | 21 ++++++++----------- test/ScriptCs.Tests/CommandFactoryTests.cs | 4 ++-- .../ExecuteScriptCommandTests.cs | 11 +++++----- test/ScriptCs.Tests/InstallCommandTests.cs | 11 +++++----- test/ScriptCs.Tests/RestoreCommandTests.cs | 16 +++++++------- test/ScriptCs.Tests/VersionCommandTests.cs | 7 +++---- 10 files changed, 43 insertions(+), 53 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 080cce7c..11c4e2e0 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -36,7 +36,6 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Logger, _scriptServiceRoot.Assembly); if (args.Restore) @@ -107,4 +106,4 @@ public ICommand CreateCommand(ScriptCsArgs args) return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: false); } } -} \ No newline at end of file +} diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index bccaff98..e62f767e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,7 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssembly _assembly; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; private readonly IConsole _console; @@ -27,7 +27,7 @@ public ExecuteReplCommand( IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssembly assembly + IAssemblyName assemblyName ) { _fileSystem = fileSystem; @@ -36,7 +36,7 @@ IAssembly assembly _filePreProcessor = filePreProcessor; _logger = logger; _console = console; - _assembly = assembly; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -96,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - _assembly.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index acfb7b28..dab313b9 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,7 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssembly _assembly; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; @@ -22,14 +22,13 @@ public ExecuteScriptCommand(string script, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, ILog logger, - IAssembly assembly) + IAssemblyName assemblyName) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; - _assembly = assembly; } public CommandResult Execute() @@ -79,7 +78,7 @@ private bool IsManagedAssembly(string path) { try { - _assembly.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index 11b885b7..cc32788a 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,7 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssembly assembly, + IAssemblyName assemblyName, IConsole console = null) { FileSystem = fileSystem; @@ -26,7 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - Assembly = assembly; + AssemblyName = assemblyName; } public IFileSystem FileSystem { get; private set; } @@ -38,6 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssembly Assembly { get; private set; } + public IAssemblyName AssemblyName { get; private set; } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 9db9f49b..54387b06 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,9 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); + var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -52,9 +52,8 @@ public void ShouldDeleteBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -80,9 +79,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -109,9 +107,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -127,4 +124,4 @@ public void ShouldDeleteAllFilesResolvedFromPackages() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index fa1444f9..deb8f88a 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,9 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); + var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 173c5a2f..263de398 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -33,9 +33,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -65,8 +64,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -116,4 +115,4 @@ public void NonManagedAssembliesAreExcluded() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index e077bed9..921d29ad 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,8 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -71,9 +71,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { @@ -90,4 +89,4 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index 7aa7f6db..ed5e3cfd 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,9 +25,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; @@ -67,9 +66,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; @@ -109,8 +107,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; @@ -132,4 +130,4 @@ public void ShouldCreateBinFolderIfItDoesNotExist() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index a5a357ea..e00cf1a4 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,9 +42,8 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -58,4 +57,4 @@ public void VersionCommandShouldOutputVersion() } } } -} \ No newline at end of file +} From fd663bdd0a4343e6f1e81b3995086cc9440b7cd8 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 13:36:01 +1000 Subject: [PATCH 0250/1224] Refactoring IAssemblyName to IAssembly Adding implementation for IAssembly interface and adding it to IoC --- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 ++++---- src/ScriptCs/Command/ExecuteScriptCommand.cs | 7 ++++--- src/ScriptCs/ScriptServiceRoot.cs | 6 +++--- test/ScriptCs.Tests/CleanCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/CommandFactoryTests.cs | 4 ++-- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/InstallCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/RestoreCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/VersionCommandTests.cs | 4 ++-- 9 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index e62f767e..bccaff98 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,7 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssemblyName _assemblyName; + private readonly IAssembly _assembly; private readonly ILog _logger; private readonly IConsole _console; @@ -27,7 +27,7 @@ public ExecuteReplCommand( IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssemblyName assemblyName + IAssembly assembly ) { _fileSystem = fileSystem; @@ -36,7 +36,7 @@ IAssemblyName assemblyName _filePreProcessor = filePreProcessor; _logger = logger; _console = console; - _assemblyName = assemblyName; + _assembly = assembly; } public CommandResult Execute() @@ -96,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - _assemblyName.GetAssemblyName(path); + _assembly.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index dab313b9..acfb7b28 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,7 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssemblyName _assemblyName; + private readonly IAssembly _assembly; private readonly ILog _logger; @@ -22,13 +22,14 @@ public ExecuteScriptCommand(string script, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, ILog logger, - IAssemblyName assemblyName) + IAssembly assembly) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; + _assembly = assembly; } public CommandResult Execute() @@ -78,7 +79,7 @@ private bool IsManagedAssembly(string path) { try { - _assemblyName.GetAssemblyName(path); + _assembly.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index cc32788a..b16b059e 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,7 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssemblyName assemblyName, + IAssembly assembly, IConsole console = null) { FileSystem = fileSystem; @@ -26,7 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - AssemblyName = assemblyName; + Assembly = assembly; } public IFileSystem FileSystem { get; private set; } @@ -38,6 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssemblyName AssemblyName { get; private set; } + public IAssembly Assembly { get; private set; } } } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 54387b06..d06f617a 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,9 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -79,8 +79,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -107,8 +107,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index deb8f88a..fa1444f9 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,9 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 263de398..c5510095 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -33,8 +33,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -64,8 +64,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 921d29ad..bd840e28 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,8 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -71,8 +71,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index ed5e3cfd..af9385f8 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,8 +25,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; @@ -66,8 +66,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; @@ -107,8 +107,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index e00cf1a4..e50770fb 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,8 +42,8 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); From 6aa6340271e75a02f9f344bc751b143b12b4b537 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 16 May 2013 12:53:08 +1000 Subject: [PATCH 0251/1224] Reverting from IAssembly to IAssemblyName --- src/ScriptCs.Core/Assembly.cs | 11 ----------- src/ScriptCs.Core/AssemblyName.cs | 10 ++++++++++ src/ScriptCs.Core/IAssemblyName.cs | 7 +++---- src/ScriptCs.Core/ScriptCs.Core.csproj | 2 +- src/ScriptCs/Command/CommandFactory.cs | 4 ++-- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 ++++---- src/ScriptCs/Command/ExecuteScriptCommand.cs | 8 ++++---- src/ScriptCs/CompositionRoot.cs | 2 +- src/ScriptCs/ScriptServiceRoot.cs | 6 +++--- test/ScriptCs.Tests/CleanCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/CommandFactoryTests.cs | 4 ++-- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 14 +++++++------- test/ScriptCs.Tests/InstallCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/RestoreCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/VersionCommandTests.cs | 4 ++-- 15 files changed, 55 insertions(+), 57 deletions(-) delete mode 100644 src/ScriptCs.Core/Assembly.cs create mode 100644 src/ScriptCs.Core/AssemblyName.cs diff --git a/src/ScriptCs.Core/Assembly.cs b/src/ScriptCs.Core/Assembly.cs deleted file mode 100644 index a2b1ec6a..00000000 --- a/src/ScriptCs.Core/Assembly.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Reflection; -namespace ScriptCs -{ - public class Assembly : IAssembly - { - public AssemblyName GetAssemblyName(string path) - { - return AssemblyName.GetAssemblyName(path); - } - } -} diff --git a/src/ScriptCs.Core/AssemblyName.cs b/src/ScriptCs.Core/AssemblyName.cs new file mode 100644 index 00000000..ffaea2b5 --- /dev/null +++ b/src/ScriptCs.Core/AssemblyName.cs @@ -0,0 +1,10 @@ +namespace ScriptCs +{ + public class AssemblyName : IAssemblyName + { + public System.Reflection.AssemblyName GetAssemblyName(string path) + { + return System.Reflection.AssemblyName.GetAssemblyName(path); + } + } +} diff --git a/src/ScriptCs.Core/IAssemblyName.cs b/src/ScriptCs.Core/IAssemblyName.cs index e4416371..3d2d9dd8 100644 --- a/src/ScriptCs.Core/IAssemblyName.cs +++ b/src/ScriptCs.Core/IAssemblyName.cs @@ -1,8 +1,7 @@ -using System.Reflection; -namespace ScriptCs +namespace ScriptCs { - public interface IAssembly + public interface IAssemblyName { - AssemblyName GetAssemblyName(string path); + System.Reflection.AssemblyName GetAssemblyName(string path); } } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 494498f7..706ab230 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -39,7 +39,7 @@ - + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 11c4e2e0..a2de5da0 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -25,7 +25,7 @@ public ICommand CreateCommand(ScriptCsArgs args) var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, - _scriptServiceRoot.Assembly); + _scriptServiceRoot.AssemblyName); return replCommand; } @@ -36,7 +36,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Assembly); + _scriptServiceRoot.AssemblyName); if (args.Restore) { diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index bccaff98..e62f767e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,7 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssembly _assembly; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; private readonly IConsole _console; @@ -27,7 +27,7 @@ public ExecuteReplCommand( IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssembly assembly + IAssemblyName assemblyName ) { _fileSystem = fileSystem; @@ -36,7 +36,7 @@ IAssembly assembly _filePreProcessor = filePreProcessor; _logger = logger; _console = console; - _assembly = assembly; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -96,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - _assembly.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index acfb7b28..e60e2ad2 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,7 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssembly _assembly; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; @@ -22,14 +22,14 @@ public ExecuteScriptCommand(string script, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, ILog logger, - IAssembly assembly) + IAssemblyName assemblyName) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; - _assembly = assembly; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -79,7 +79,7 @@ private bool IsManagedAssembly(string path) { try { - _assembly.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 9ffea091..94d36a7f 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -48,7 +48,7 @@ public void Initialize() typeof (NugetInstallationProvider), typeof (PackageInstaller), typeof (ReplConsole), - typeof (Assembly) + typeof (AssemblyName) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index b16b059e..cc32788a 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,7 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssembly assembly, + IAssemblyName assemblyName, IConsole console = null) { FileSystem = fileSystem; @@ -26,7 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - Assembly = assembly; + AssemblyName = assemblyName; } public IFileSystem FileSystem { get; private set; } @@ -38,6 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssembly Assembly { get; private set; } + public IAssemblyName AssemblyName { get; private set; } } } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index d06f617a..54387b06 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,9 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); + var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -79,8 +79,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -107,8 +107,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index fa1444f9..deb8f88a 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,9 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); + var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c5510095..60bead91 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -33,8 +33,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -64,8 +64,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -100,10 +100,10 @@ public void NonManagedAssembliesAreExcluded() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - assembly.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); + var assemblyName = new Mock(); + assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index bd840e28..921d29ad 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,8 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -71,8 +71,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index af9385f8..ed5e3cfd 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,8 +25,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; @@ -66,8 +66,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; @@ -107,8 +107,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index e50770fb..e00cf1a4 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,8 +42,8 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); From 83fbb5925c54f158895777999a65dc5ab46ee173 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 16 May 2013 13:28:49 +1000 Subject: [PATCH 0252/1224] Some fixes from a bad rebase --- common/CommonVersionInfo.cs | 21 +++++++++++++------ src/ScriptCs/Command/CommandFactory.cs | 1 + .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index 590a13eb..270505b9 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,9 +1,18 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18033 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; using System.Reflection; -/** - * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the - * contents of 'build\ScriptCs.Version.props'. - **/ +[assembly: System.Reflection.AssemblyVersionAttribute("0.5.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("0.5.0-alpha")] + +// Generated by the MSBuild WriteCodeFragment class on 16/05/2013 1:24:46 PM. -[assembly: AssemblyVersion("0.0.0")] -[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index a2de5da0..7e676bae 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -36,6 +36,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, + _scriptServiceRoot.Logger, _scriptServiceRoot.AssemblyName); if (args.Restore) diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index 9dc8d1b7..d98de537 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -35,6 +35,7 @@ public void ShouldPromptForInput() Mock.Of(), Mock.Of(), Mock.Of(), + Mock.Of(), console); var commandFactory = new CommandFactory(root); From 47d6b432bc15ac878cd975b2ae19805bdff2c7cc Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Thu, 16 May 2013 14:17:21 +0200 Subject: [PATCH 0253/1224] Added missing method call to IConsole.Exit(). --- src/ScriptCs/Repl.cs | 2 ++ test/ScriptCs.Tests/ReplTests.cs | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index d54775de..7f47494d 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -49,6 +49,8 @@ public void Terminate() { Logger.Debug("Terminating packs"); ScriptPackSession.TerminatePacks(); + Logger.Debug("Exiting console"); + Console.Exit(); } public void Execute(string script) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 71729348..1fc45011 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -114,6 +114,12 @@ public void TerminatesScriptPacks() { _mocks.ScriptPack.Verify(x => x.Terminate()); } + + [Fact] + public void ExitsTheConsole() + { + _mocks.Console.Verify(x => x.Exit()); + } } public class TheExecuteMethod From e3fb3679cd11d800a809d0003f1bc0e50dfe0408 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 16 May 2013 22:56:13 -0400 Subject: [PATCH 0254/1224] added System.IO --- src/ScriptCs.Core/ScriptExecutor.cs | 2 +- src/ScriptCs/Repl.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index e6e675fc..14641fff 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -9,7 +9,7 @@ namespace ScriptCs public class ScriptExecutor : IScriptExecutor { private static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; + private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; private readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 1db41eb6..c6cdfa90 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -11,7 +11,7 @@ namespace ScriptCs public class Repl { public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; + public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; public IFileSystem FileSystem { get; private set; } public IScriptEngine ScriptEngine { get; private set; } From b9795942cbdbe6789d0c735ee49cf9829ebd56e7 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 16 May 2013 22:57:29 -0400 Subject: [PATCH 0255/1224] fixed namespaces in the test --- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 19bd6806..0224b23e 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -217,7 +217,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() [Fact] public void ExecutorShouldPassDefaultNamespacesToEngine() { - var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; + var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); From 17226998202c8413dd2a5bcf81e0d2537027553c Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 18 May 2013 19:08:14 +0200 Subject: [PATCH 0256/1224] Added overload for processing in-memory script. Fixes #246. --- src/ScriptCs.Core/FilePreProcessor.cs | 75 +++++++++++-------- src/ScriptCs.Core/FilePreProcessorResult.cs | 4 +- src/ScriptCs.Core/FileSystem.cs | 5 ++ src/ScriptCs.Core/IFilePreProcessor.cs | 6 +- src/ScriptCs.Core/IFileSystem.cs | 2 + .../ScriptCs.Core.Tests/FileProcessorTests.cs | 6 +- 6 files changed, 62 insertions(+), 36 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index db03bacd..136362d9 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -22,59 +22,74 @@ public FilePreProcessor(IFileSystem fileSystem, ILog logger) public FilePreProcessorResult ProcessFile(string path) { - var context = new FilePreProcessContext(); + return Parse(context => ParseFile(path, context)); + } + + public FilePreProcessorResult ProcessScript(string script) + { + var scriptLines = _fileSystem.SplitLines(script).ToList(); + return Parse(context => ParseScript(scriptLines, context)); + } + + private FilePreProcessorResult Parse(Action parseAction) + { + var context = new FilePreProcessorContext(); _logger.DebugFormat("Starting pre-processing"); - ParseFile(path, context); + parseAction(context); - var code = GenerateScript(context); + var code = GenerateCode(context); _logger.DebugFormat("Pre-processing finished successfully"); return new FilePreProcessorResult { - Usings = context.Usings, + UsingStatements = context.UsingStatements, LoadedScripts = context.LoadedScripts, References = context.References, Code = code }; } - private static string GenerateScript(FilePreProcessContext context) + private static string GenerateCode(FilePreProcessorContext context) { var stringBuilder = new StringBuilder(); - AppendUsings(stringBuilder, context.Usings); + var usingLines = context.UsingStatements + .Select(item => string.Format("using {0};", item)) + .ToList(); + + if (usingLines.Count > 0) + { + stringBuilder.AppendLine(string.Join(Environment.NewLine, usingLines)); + stringBuilder.AppendLine(); // Insert a blank separator line + } stringBuilder.Append(string.Join(Environment.NewLine, context.Body)); return stringBuilder.ToString(); } - private static void AppendUsings(StringBuilder stringBuilder, IEnumerable items) + private void ParseFile(string path, FilePreProcessorContext context) { - var lines = items.Distinct().Select(item => string.Format("using {0};", item)).ToList(); + _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); - if (lines.Count == 0) return; + var scriptLines = _fileSystem.ReadFileLines(path).ToList(); - stringBuilder.AppendLine(string.Join(Environment.NewLine, lines)); - stringBuilder.AppendLine(); // Insert a blank separator line + ParseScript(scriptLines, context, path); } - private void ParseFile(string path, FilePreProcessContext context) + private void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) { - _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); - - var fileLines = _fileSystem.ReadFileLines(path).ToList(); - - InsertLineDirective(path, fileLines); + // Insert line directive if there's a path + if (path != null) InsertLineDirective(path, scriptLines); - var codeIndex = fileLines.FindIndex(PreProcessorUtil.IsNonDirectiveLine); + var codeIndex = scriptLines.FindIndex(PreProcessorUtil.IsNonDirectiveLine); - for (var index = 0; index < fileLines.Count; index++) + for (var index = 0; index < scriptLines.Count; index++) { - ProcessLine(context, fileLines[index], index < codeIndex || codeIndex < 0); + ProcessLine(context, scriptLines[index], index < codeIndex || codeIndex < 0); } context.LoadedScripts.Add(path); @@ -89,14 +104,14 @@ private static void InsertLineDirective(string path, List fileLines) fileLines.Insert(bodyIndex, directiveLine); } - private void ProcessLine(FilePreProcessContext context, string line, bool isBeforeCode) + private void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) { if (PreProcessorUtil.IsUsingLine(line)) { var @using = PreProcessorUtil.GetPath(PreProcessorUtil.UsingString, line); - if (!context.Usings.Contains(@using)) + if (!context.UsingStatements.Contains(@using)) { - context.Usings.Add(@using); + context.UsingStatements.Add(@using); } return; @@ -107,7 +122,7 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo if (isBeforeCode) { var reference = PreProcessorUtil.GetPath(PreProcessorUtil.RString, line); - if (!context.References.Contains(reference)) + if (!string.IsNullOrWhiteSpace(reference) && !context.References.Contains(reference)) { context.References.Add(reference); } @@ -121,7 +136,7 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo if (isBeforeCode) { var filePath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); - if (!context.LoadedScripts.Contains(filePath)) + if (!string.IsNullOrWhiteSpace(filePath) && !context.LoadedScripts.Contains(filePath)) { ParseFile(filePath, context); } @@ -134,17 +149,17 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo context.Body.Add(line); } - private class FilePreProcessContext + private class FilePreProcessorContext { - public FilePreProcessContext() + public FilePreProcessorContext() { - Usings = new List(); + UsingStatements = new List(); References = new List(); LoadedScripts = new List(); Body = new List(); } - public List Usings { get; private set; } + public List UsingStatements { get; private set; } public List References { get; private set; } @@ -153,4 +168,4 @@ public FilePreProcessContext() public List Body { get; private set; } } } -} \ No newline at end of file +} diff --git a/src/ScriptCs.Core/FilePreProcessorResult.cs b/src/ScriptCs.Core/FilePreProcessorResult.cs index 94c27ee9..f5731ebe 100644 --- a/src/ScriptCs.Core/FilePreProcessorResult.cs +++ b/src/ScriptCs.Core/FilePreProcessorResult.cs @@ -6,12 +6,12 @@ public class FilePreProcessorResult { public FilePreProcessorResult() { - Usings = new List(); + UsingStatements = new List(); LoadedScripts = new List(); References = new List(); } - public List Usings { get; set; } + public List UsingStatements { get; set; } public List LoadedScripts { get; set; } diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index aed7e297..d8e0bb25 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -76,6 +76,11 @@ public void FileDelete(string path) File.Delete(path); } + public IEnumerable SplitLines(string value) + { + return value.Split(new[] { NewLine }, StringSplitOptions.None); + } + public Stream CreateFileStream(string filePath, FileMode mode) { return new FileStream(filePath, mode); diff --git a/src/ScriptCs.Core/IFilePreProcessor.cs b/src/ScriptCs.Core/IFilePreProcessor.cs index b136cc24..5fb0a688 100644 --- a/src/ScriptCs.Core/IFilePreProcessor.cs +++ b/src/ScriptCs.Core/IFilePreProcessor.cs @@ -1,7 +1,11 @@ -namespace ScriptCs +using System.Collections.Generic; + +namespace ScriptCs { public interface IFilePreProcessor { FilePreProcessorResult ProcessFile(string path); + + FilePreProcessorResult ProcessScript(string script); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 35ce813f..253be305 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -36,6 +36,8 @@ public interface IFileSystem void FileDelete(string path); + IEnumerable SplitLines(string value); + Stream CreateFileStream(string filePath, FileMode mode); } } \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index 3fdd1d68..ec669b3f 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -126,9 +126,9 @@ public void ShouldReturnResultWithAllUsings() var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var result = processor.ProcessFile("script1.csx"); - result.Usings.Count.ShouldEqual(2); - result.Usings.ShouldContain("System"); - result.Usings.ShouldContain("System.Core"); + result.UsingStatements.Count.ShouldEqual(2); + result.UsingStatements.ShouldContain("System"); + result.UsingStatements.ShouldContain("System.Core"); } [Fact] From 73e81114c3d5c22778d0886f75e4e0a42e0b93af Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 19 May 2013 16:59:40 +0200 Subject: [PATCH 0257/1224] Added automatic installation of packages when packages.config is present, but no packages folder. Fixes #251 --- src/ScriptCs/Command/CommandFactory.cs | 24 +++++++++++++++++ test/ScriptCs.Tests/CommandFactoryTests.cs | 27 ++++++++++++++++++- .../ExecuteScriptCommandTests.cs | 4 +++ test/ScriptCs.Tests/RestoreCommandTests.cs | 3 +++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 7e676bae..4fa1c33f 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -39,6 +39,30 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.Logger, _scriptServiceRoot.AssemblyName); + var fileSystem = _scriptServiceRoot.FileSystem; + var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; + var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); + var packagesFolder = Path.Combine(currentDirectory, Constants.PackagesFolder); + + if (fileSystem.FileExists(packageFile) && !fileSystem.DirectoryExists(packagesFolder)) + { + var installCommand = new InstallCommand( + null, + false, + fileSystem, + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.PackageInstaller, + _scriptServiceRoot.Logger); + + var restoreCommand = new RestoreCommand( + args.Install, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.Logger); + + return new CompositeCommand(installCommand, restoreCommand, executeCommand); + } + if (args.Restore) { var restoreCommand = new RestoreCommand( diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index deb8f88a..c479b1cd 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -11,14 +11,16 @@ public class CommandFactoryTests { public class CreateCommandMethod { - private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) + private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool packagesFolderExists = true) { const string CurrentDirectory = "C:\\"; const string PackagesFile = "C:\\packages.config"; + const string PackagesFolder = "C:\\packages"; var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); fs.Setup(x => x.FileExists(PackagesFile)).Returns(packagesFileExists); + fs.Setup(x => x.DirectoryExists(PackagesFolder)).Returns(packagesFolderExists); var resolver = new Mock(); var executor = new Mock(); @@ -92,6 +94,29 @@ public void ShouldExecuteWhenScriptNameIsPassed() result.ShouldImplement(); } + [Fact] + public void ShouldInstallAndExecuteWhenScriptNameIsPassedAndPackagesFolderDoesNotExist() + { + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = null, + ScriptName = "test.csx" + }; + + var root = CreateRoot(packagesFileExists: true, packagesFolderExists: false); + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + var compositeCommand = result as ICompositeCommand; + compositeCommand.ShouldNotBeNull(); + + compositeCommand.Commands.Count.ShouldEqual(3); + compositeCommand.Commands[0].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); + compositeCommand.Commands[2].ShouldImplement(); + } + [Fact] public void ShouldExecuteWhenBothNameAndInstallArePassed() { diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 60bead91..55640149 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -26,6 +26,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() }; var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + var resolver = new Mock(); var executor = new Mock(); var engine = new Mock(); @@ -55,6 +57,7 @@ public void ShouldCreateMissingBinFolder() var fs = new Mock(); fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(WorkingDirectory); fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); var resolver = new Mock(); @@ -88,6 +91,7 @@ public void NonManagedAssembliesAreExcluded() }; var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "managed.dll", nonManaged diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index ed5e3cfd..eb80a41a 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -37,6 +37,7 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var destWriteTime = sourceWriteTime; fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); @@ -78,6 +79,7 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var destWriteTime = new DateTime(2013, 2, 7); fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); @@ -114,6 +116,7 @@ public void ShouldCreateBinFolderIfItDoesNotExist() const string BinFolder = @"C:\bin"; fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); var binFolderCreated = false; From 0a76954f85b82ad43ea408bddfed94f31282a909 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 19 May 2013 18:31:40 +0200 Subject: [PATCH 0258/1224] Minor tweak :) --- src/ScriptCs/Command/CommandFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 4fa1c33f..b35aff8f 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -40,7 +40,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.AssemblyName); var fileSystem = _scriptServiceRoot.FileSystem; - var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; + var currentDirectory = fileSystem.CurrentDirectory; var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); var packagesFolder = Path.Combine(currentDirectory, Constants.PackagesFolder); From 22c9cd9c96df4e818fdc5a6e5072daaa8697d854 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 21 May 2013 13:25:37 +0200 Subject: [PATCH 0259/1224] Replaced Environment.NewLine with _fileSystem.NewLine --- src/ScriptCs.Core/FilePreProcessor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 136362d9..e50c0910 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -52,7 +52,7 @@ private FilePreProcessorResult Parse(Action parseAction }; } - private static string GenerateCode(FilePreProcessorContext context) + private string GenerateCode(FilePreProcessorContext context) { var stringBuilder = new StringBuilder(); @@ -62,11 +62,11 @@ private static string GenerateCode(FilePreProcessorContext context) if (usingLines.Count > 0) { - stringBuilder.AppendLine(string.Join(Environment.NewLine, usingLines)); + stringBuilder.AppendLine(string.Join(_fileSystem.NewLine, usingLines)); stringBuilder.AppendLine(); // Insert a blank separator line } - stringBuilder.Append(string.Join(Environment.NewLine, context.Body)); + stringBuilder.Append(string.Join(_fileSystem.NewLine, context.Body)); return stringBuilder.ToString(); } From 0f49393fe889315c1ac0876c198349ea5eb49320 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 21 May 2013 14:02:55 +0200 Subject: [PATCH 0260/1224] Added tests for ProcessScript method --- src/ScriptCs.Core/FilePreProcessor.cs | 2 +- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index e50c0910..4196aca1 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -92,7 +92,7 @@ private void ParseScript(List scriptLines, FilePreProcessorContext conte ProcessLine(context, scriptLines[index], index < codeIndex || codeIndex < 0); } - context.LoadedScripts.Add(path); + if (path != null) context.LoadedScripts.Add(path); } private static void InsertLineDirective(string path, List fileLines) diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index ec669b3f..84d574b7 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -400,5 +400,55 @@ public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() fileLines[line].ShouldEqual(f1[4]); } } + + public class ProcessScriptMethod + { + private readonly Mock _fileSystem; + + public ProcessScriptMethod() + { + _fileSystem = new Mock(); + _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); + } + + [Fact] + public void ShouldSplitScriptIntoLines() + { + var preProcessor = new FilePreProcessor(_fileSystem.Object, Mock.Of()); + var script = @"Console.WriteLine(""Testing..."");"; + + preProcessor.ProcessScript(script); + + _fileSystem.Verify(x => x.SplitLines(script), Times.Once()); + } + + [Fact] + public void ShouldNotReadFromFile() + { + var preProcessor = new FilePreProcessor(_fileSystem.Object, Mock.Of()); + var script = @"Console.WriteLine(""Testing..."");"; + + preProcessor.ProcessScript(script); + + _fileSystem.Verify(x => x.ReadFileLines(It.IsAny()), Times.Never()); + } + + [Fact] + public void ShouldNotIncludeLineDirectiveForRootScript() + { + var script1 = new List { @"Console.WriteLine(""Hello from script1.csx""" }; + _fileSystem.Setup(x => x.ReadFileLines("script1.csx")).Returns(script1.ToArray()); + _fileSystem.Setup(x => x.SplitLines(It.IsAny())) + .Returns(x => x.Split(new[] { Environment.NewLine }, StringSplitOptions.None)); + + var preProcessor = new FilePreProcessor(_fileSystem.Object, Mock.Of()); + var script = @"#load script1.csx"; + + var result = preProcessor.ProcessScript(script); + var fileLines = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + + fileLines.Count(x => x.StartsWith("#line ")).ShouldEqual(1); + } + } } } \ No newline at end of file From 9a1d95efae055ca7e236e9530c704dd2bfa3a29e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 21 May 2013 18:45:08 +0200 Subject: [PATCH 0261/1224] Added ScriptPack base class --- src/ScriptCs.Contracts/IScriptPack.cs | 12 ++++++++++-- src/ScriptCs.Contracts/ScriptCs.Contracts.csproj | 1 + src/ScriptCs.Contracts/ScriptPack.cs | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/ScriptCs.Contracts/ScriptPack.cs diff --git a/src/ScriptCs.Contracts/IScriptPack.cs b/src/ScriptCs.Contracts/IScriptPack.cs index c22f6999..8c3b35b2 100644 --- a/src/ScriptCs.Contracts/IScriptPack.cs +++ b/src/ScriptCs.Contracts/IScriptPack.cs @@ -6,7 +6,15 @@ namespace ScriptCs.Contracts public interface IScriptPack { void Initialize(IScriptPackSession session); - IScriptPackContext GetContext(); + + IScriptPackContext GetContext(); + void Terminate(); } -} + + public interface IScriptPack : IScriptPack where TContext : IScriptPackContext + { + [Import] + TContext Context { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 3f667d25..707c4ecb 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -30,6 +30,7 @@ Properties\CommonVersionInfo.cs + diff --git a/src/ScriptCs.Contracts/ScriptPack.cs b/src/ScriptCs.Contracts/ScriptPack.cs new file mode 100644 index 00000000..e8dce6b1 --- /dev/null +++ b/src/ScriptCs.Contracts/ScriptPack.cs @@ -0,0 +1,16 @@ +namespace ScriptCs.Contracts +{ + public abstract class ScriptPack : IScriptPack where TContext : IScriptPackContext + { + public TContext Context { get; set; } + + public virtual void Initialize(IScriptPackSession session) { } + + public virtual IScriptPackContext GetContext() + { + return Context; + } + + public virtual void Terminate() { } + } +} \ No newline at end of file From 428b4ae690daf92e884bdc9fec79ea9a16d8f3d5 Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Thu, 2 May 2013 16:54:06 -0700 Subject: [PATCH 0262/1224] Implement `Args` to pass arguments to scripts. --- src/ScriptCs.Core/IScriptEngine.cs | 2 +- src/ScriptCs.Core/IScriptExecutor.cs | 2 +- src/ScriptCs.Core/IScriptHostFactory.cs | 2 +- src/ScriptCs.Core/ScriptExecutor.cs | 4 +-- src/ScriptCs.Core/ScriptHost.cs | 4 ++- src/ScriptCs.Core/ScriptHostFactory.cs | 4 +-- .../RoslynScriptEngine.cs | 4 +-- src/ScriptCs/Command/CommandFactory.cs | 7 +++-- src/ScriptCs/Command/ExecuteScriptCommand.cs | 11 ++++--- src/ScriptCs/Program.cs | 7 ++++- src/ScriptCs/Repl.cs | 2 +- src/ScriptCs/ScriptCsArgs.cs | 5 +++- .../ScriptExecutorTests.cs | 30 +++++++++---------- test/ScriptCs.Core.Tests/ScriptHostTests.cs | 2 +- .../RoslynScriptDebuggerEngine.cs | 2 +- .../RoslynScriptEngineTests.cs | 18 +++++------ test/ScriptCs.Tests/CleanCommandTests.cs | 8 ++--- test/ScriptCs.Tests/CommandFactoryTests.cs | 20 ++++++------- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 2 +- .../ExecuteScriptCommandTests.cs | 10 +++---- test/ScriptCs.Tests/InstallCommandTests.cs | 4 +-- test/ScriptCs.Tests/ReplTests.cs | 10 +++---- test/ScriptCs.Tests/RestoreCommandTests.cs | 6 ++-- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 24 files changed, 91 insertions(+), 77 deletions(-) diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index e22ab9c5..94740e2b 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -5,6 +5,6 @@ namespace ScriptCs public interface IScriptEngine { string BaseDirectory { get; set; } - object Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); + object Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptExecutor.cs b/src/ScriptCs.Core/IScriptExecutor.cs index 07ca8b8f..80c8e313 100644 --- a/src/ScriptCs.Core/IScriptExecutor.cs +++ b/src/ScriptCs.Core/IScriptExecutor.cs @@ -5,6 +5,6 @@ namespace ScriptCs { public interface IScriptExecutor { - void Execute(string script, IEnumerable paths, IEnumerable recipes); + void Execute(string script, string[] scriptArgs, IEnumerable paths, IEnumerable recipes); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptHostFactory.cs b/src/ScriptCs.Core/IScriptHostFactory.cs index 469e8068..8f7f7c3a 100644 --- a/src/ScriptCs.Core/IScriptHostFactory.cs +++ b/src/ScriptCs.Core/IScriptHostFactory.cs @@ -6,6 +6,6 @@ namespace ScriptCs { public interface IScriptHostFactory { - ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager); + ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs); } } diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 14641fff..81fc0284 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -24,7 +24,7 @@ public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor _logger = logger; } - public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) + public void Execute(string script, string[] scriptArgs, IEnumerable paths, IEnumerable scriptPacks) { var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); @@ -42,7 +42,7 @@ public void Execute(string script, IEnumerable paths, IEnumerable() where T:IScriptPackContext diff --git a/src/ScriptCs.Core/ScriptHostFactory.cs b/src/ScriptCs.Core/ScriptHostFactory.cs index c2b86317..2b07f587 100644 --- a/src/ScriptCs.Core/ScriptHostFactory.cs +++ b/src/ScriptCs.Core/ScriptHostFactory.cs @@ -5,9 +5,9 @@ namespace ScriptCs { public class ScriptHostFactory : IScriptHostFactory { - public ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager) + public ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs) { - return new ScriptHost(scriptPackManager); + return new ScriptHost(scriptPackManager, scriptArgs); } } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 50036033..e011eb8d 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -28,7 +28,7 @@ public string BaseDirectory set { _scriptEngine.BaseDirectory = value; } } - public object Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) + public object Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { Guard.AgainstNullArgument("scriptPackSession", scriptPackSession); @@ -40,7 +40,7 @@ public object Execute(string code, IEnumerable references, IEnumerable(), Enumerable.Empty()); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), Enumerable.Empty()); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -65,7 +65,7 @@ public void DoNotChangePathIfAbsolute() preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Execute(@"c:\my_script\script.csx", new string[0], Enumerable.Empty(), Enumerable.Empty()); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -92,7 +92,7 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() IEnumerable recipes = Enumerable.Empty(); // act - scriptExecutor.Execute(scriptName, paths, recipes); + scriptExecutor.Execute(scriptName, new string[0], paths, recipes); // assert string expectedBaseDirectory = Path.Combine(currentDirectory, "bin"); @@ -123,15 +123,15 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut var recipes = Enumerable.Empty(); preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(new FilePreProcessorResult { Code = code }).Verifiable(); - scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(code, It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); // act - scriptExecutor.Execute(scriptName, paths, recipes); + scriptExecutor.Execute(scriptName, new string[0], paths, recipes); // assert preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); - scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); + scriptEngine.Verify(s => s.Execute(code, It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); } @@ -162,13 +162,13 @@ public void ShouldAddReferenceToEachDestinationFile() var destPaths = new string[] { "System", "System.Core", destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; - scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); // act - scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); + scriptExecutor.Execute(scriptName, new string[0], paths, Enumerable.Empty()); // assert - scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); } [Fact] @@ -187,7 +187,7 @@ public void ShouldInitializeScriptPacks() scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), new[] { scriptPack1.Object }); scriptPack1.Verify(p => p.Initialize(It.IsAny())); } @@ -209,7 +209,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); scriptPack1.Setup(p => p.Terminate()); - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), new[] { scriptPack1.Object }); scriptPack1.Verify(p => p.Terminate()); } @@ -230,9 +230,9 @@ public void ExecutorShouldPassDefaultNamespacesToEngine() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), Enumerable.Empty()); - engine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); + engine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); } [Fact] @@ -251,9 +251,9 @@ public void ExecutorShouldPassDefaultReferencesToEngine() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), Enumerable.Empty()); - engine.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Except(defaultReferences).Any()), It.IsAny>(), It.IsAny()), Times.Exactly(1)); + engine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.Is>(x => !x.Except(defaultReferences).Any()), It.IsAny>(), It.IsAny()), Times.Exactly(1)); } } } diff --git a/test/ScriptCs.Core.Tests/ScriptHostTests.cs b/test/ScriptCs.Core.Tests/ScriptHostTests.cs index 4f03b375..3a80cd59 100644 --- a/test/ScriptCs.Core.Tests/ScriptHostTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptHostTests.cs @@ -21,7 +21,7 @@ public class TheGetMethod public TheGetMethod() { - _scriptHost = new ScriptHost(_mockScriptPackManager.Object); + _scriptHost = new ScriptHost(_mockScriptPackManager.Object, new string[0]); _mockScriptPackManager.Setup(s => s.Get()).Returns(_mockContext.Object); } diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs index 9c06e4ed..9e0d3082 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs @@ -38,7 +38,7 @@ public void ShouldThrowExceptionThrownByScriptWhenErrorOccurs() var exception = Assert.Throws( () => scriptEngine.Execute( - code, Enumerable.Empty(), Enumerable.Empty(), new ScriptPackSession(Enumerable.Empty()))); + code, new string[0], Enumerable.Empty(), Enumerable.Empty(), new ScriptPackSession(Enumerable.Empty()))); Console.WriteLine(exception.Message); diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index ac01346b..21780bc6 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -54,7 +54,7 @@ public class TheExecuteMethod public void ShouldCreateScriptHostWithContexts() { var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); var code = "var a = 0;"; @@ -66,16 +66,16 @@ public void ShouldCreateScriptHostWithContexts() var scriptPackSession = new ScriptPackSession(new[] { scriptPack1.Object }); - engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); + engine.Execute(code, new string[0], Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); - scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny())); + scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny(), It.IsAny())); } [Fact] public void ShouldReuseExistingSessionIfProvided() { var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); var code = "var a = 0;"; @@ -84,7 +84,7 @@ public void ShouldReuseExistingSessionIfProvided() var roslynEngine = new ScriptEngine(); var session = new SessionState {Session = roslynEngine.CreateSession()}; scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; - engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); + engine.Execute(code, new string[0], Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); engine.Session.ShouldEqual(session.Session); } @@ -92,13 +92,13 @@ public void ShouldReuseExistingSessionIfProvided() public void ShouldCreateNewSessionIfNotProvided() { var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); var code = "var a = 0;"; var engine = CreateTestScriptEngine(scriptHostFactory: scriptHostFactory); var scriptPackSession = new ScriptPackSession(new List()); - engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); + engine.Execute(code, new string[0], Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); engine.Session.ShouldNotBeNull(); } @@ -106,7 +106,7 @@ public void ShouldCreateNewSessionIfNotProvided() public void ShouldAddNewReferencesIfTheyAreProvided() { var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); var code = "var a = 0;"; @@ -115,7 +115,7 @@ public void ShouldAddNewReferencesIfTheyAreProvided() var roslynEngine = new ScriptEngine(); var session = new SessionState { Session = roslynEngine.CreateSession()}; scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; - engine.Execute(code, new[] {"System"}, Enumerable.Empty(), scriptPackSession); + engine.Execute(code, new string[0], new[] {"System"}, Enumerable.Empty(), scriptPackSession); ((SessionState)scriptPackSession.State[RoslynScriptEngine.SessionKey]).References.Count().ShouldEqual(1); } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 54387b06..cae08c14 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -31,7 +31,7 @@ public void ShouldDeletePackagesFolder() fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -58,7 +58,7 @@ public void ShouldDeleteBinFolder() fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -87,7 +87,7 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -116,7 +116,7 @@ public void ShouldDeleteAllFilesResolvedFromPackages() resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index c479b1cd..b8be9568 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -46,7 +46,7 @@ public void ShouldInstallAndRestoreWhenInstallFlagIsOn() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -67,7 +67,7 @@ public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExist }; var factory = new CommandFactory(CreateRoot(packagesFileExists: false)); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -89,7 +89,7 @@ public void ShouldExecuteWhenScriptNameIsPassed() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldImplement(); } @@ -106,7 +106,7 @@ public void ShouldInstallAndExecuteWhenScriptNameIsPassedAndPackagesFolderDoesNo var root = CreateRoot(packagesFileExists: true, packagesFolderExists: false); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -128,7 +128,7 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldImplement(); } @@ -139,7 +139,7 @@ public void ShouldRestoreWhenBothNameAndRestoreArePassed() var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -155,7 +155,7 @@ public void ShouldSaveAndCleanWhenCleanFlagIsPassed() var args = new ScriptCsArgs { Clean = true, ScriptName = null }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -171,7 +171,7 @@ public void ShouldSaveWhenSaveFlagIsPassed() var args = new ScriptCsArgs { Save = true, ScriptName = null }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldNotBeNull(); result.ShouldImplement(); @@ -188,7 +188,7 @@ public void ShouldReturnInvalidWhenNoNameOrInstallSet() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldImplement(); } @@ -202,7 +202,7 @@ public void ShouldReturnHelpCommandWhenHelpIsPassed() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldImplement(); } diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index d98de537..7e254743 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -40,7 +40,7 @@ public void ShouldPromptForInput() var commandFactory = new CommandFactory(root); - var target = commandFactory.CreateCommand(new ScriptCsArgs { Repl = true }); + var target = commandFactory.CreateCommand(new ScriptCsArgs { Repl = true }, new string[0]); target.Execute(); diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 55640149..453393b1 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -39,11 +39,11 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); - executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny>(), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny(), It.IsAny>(), It.IsAny>()), Times.Once()); } [Fact] @@ -71,7 +71,7 @@ public void ShouldCreateMissingBinFolder() var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -111,11 +111,11 @@ public void NonManagedAssembliesAreExcluded() var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); - executor.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); } } } diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 921d29ad..13c9ebbc 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -41,7 +41,7 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -81,7 +81,7 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 002a0930..72bd8219 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -150,14 +150,14 @@ public void ResetsColorAfterExecutingScript() [Fact] public void CallsExecuteOnTheScriptEngine() { - _mocks.ScriptEngine.Verify(x => x.Execute("foo", _repl.References, Repl.DefaultNamespaces, It.IsAny())); + _mocks.ScriptEngine.Verify(x => x.Execute("foo", new string[0], _repl.References, Repl.DefaultNamespaces, It.IsAny())); } [Fact] public void CatchesExceptionsAndWritesThemInRed() { _mocks.ScriptEngine.Setup( - x => x.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())) + x => x.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())) .Throws(); _repl.Execute("foo"); @@ -196,7 +196,7 @@ public void ShouldExecuteLoadedFileIfLineIsALoad() _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); - mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); } [Fact] @@ -208,7 +208,7 @@ public void ShouldNotExecuteLoadedFileIfFileDoesNotExist() _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); - mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); } [Fact] @@ -250,7 +250,7 @@ public void ShouldNotExecuteAnythingIfLineIsAReference() _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); _repl.Execute("#r \"my.dll\""); - mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); } } } diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index eb80a41a..7ee7559a 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -45,7 +45,7 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -87,7 +87,7 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -124,7 +124,7 @@ public void ShouldCreateBinFolderIfItDoesNotExist() fs.Setup(x => x.CreateDirectory(BinFolder)).Callback(() => binFolderCreated = true).Verifiable(); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index e00cf1a4..bbc7f11e 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -46,7 +46,7 @@ public void VersionCommandShouldOutputVersion() var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); // clear the fake console output _outputText.Clear(); From d9bb35bf17b9d87f27c829e446e51d17af9b89da Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Mon, 13 May 2013 09:43:05 -0700 Subject: [PATCH 0263/1224] Rename Args to ScriptArgs for clarity. --- src/ScriptCs.Core/ScriptHost.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/ScriptHost.cs b/src/ScriptCs.Core/ScriptHost.cs index 658d8ba7..02401976 100644 --- a/src/ScriptCs.Core/ScriptHost.cs +++ b/src/ScriptCs.Core/ScriptHost.cs @@ -7,12 +7,12 @@ namespace ScriptCs public class ScriptHost { private IScriptPackManager _scriptPackManager; - public string[] Args { get; private set; } + public string[] ScriptArgs { get; private set; } public ScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs) { _scriptPackManager = scriptPackManager; - Args = scriptArgs; + ScriptArgs = scriptArgs; } public T Require() where T:IScriptPackContext From 881a78eb09c5dfb21070b79535872da7607e188b Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Mon, 13 May 2013 09:44:02 -0700 Subject: [PATCH 0264/1224] Unit tests for `--` parsing on command line. --- src/ScriptCs/ScriptCsArgs.cs | 12 +++ test/ScriptCs.Tests/ScriptArgsTests.cs | 107 ++++++++++++++++++++++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 + 3 files changed, 120 insertions(+) create mode 100644 test/ScriptCs.Tests/ScriptArgsTests.cs diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 78064e71..fd0440aa 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -53,5 +53,17 @@ public class ScriptCsArgs [ArgShortcut("version")] [ArgDescription("Outputs version information")] public bool Version { get; set; } + + public static void SplitScriptArgs(ref string[] args, out string[] scriptArgs) + { + // Split the arguments list on "--". + // The arguments before the "--" (or all arguments if there is no "--") are + // for ScriptCs.exe, and the arguments after that are for the csx script. + int separatorLocation = Array.IndexOf(args, "--"); + int scriptArgsCount = separatorLocation == -1 ? 0 : args.Length - separatorLocation - 1; + scriptArgs = new string[scriptArgsCount]; + Array.Copy(args, separatorLocation + 1, scriptArgs, 0, scriptArgsCount); + if (separatorLocation != -1) args = args.Take(separatorLocation).ToArray(); + } } } \ No newline at end of file diff --git a/test/ScriptCs.Tests/ScriptArgsTests.cs b/test/ScriptCs.Tests/ScriptArgsTests.cs new file mode 100644 index 00000000..10e8f5b8 --- /dev/null +++ b/test/ScriptCs.Tests/ScriptArgsTests.cs @@ -0,0 +1,107 @@ +using System; +using Common.Logging; +using Moq; +using ScriptCs.Command; +using ScriptCs.Package; +using Xunit; + +namespace ScriptCs.Tests +{ + public class ScriptArgsTests + { + public class SplitScriptArgsMethod + { + [Fact] + public void ShouldHandleEmptyArgs() + { + string[] args = new string[0]; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[0], args); + Assert.Equal(new string[0], scriptArgs); + } + + [Fact] + public void ShouldHandleMissingDoubledash() + { + string[] args = new string[] { "scriptname.csx", "-restore" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); + Assert.Equal(new string[0], scriptArgs); + } + + [Fact] + public void ShouldHandleArgsAndScriptArgs() + { + string[] args = new string[] { "scriptname.csx", "-restore", "--", "-port", "8080" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); + Assert.Equal(new string[] { "-port", "8080" }, scriptArgs); + } + + [Fact] + public void ShouldHandleJustScriptArgs() + { + string[] args = new string[] { "--", "-port", "8080" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[0], args); + Assert.Equal(new string[] { "-port", "8080" }, scriptArgs); + } + + [Fact] + public void ShouldHandleJustDoubledash() + { + string[] args = new string[] { "--" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[0], args); + Assert.Equal(new string[0], scriptArgs); + } + + [Fact] + public void ShouldHandleExtraDoubledash() + { + string[] args = new string[] { "scriptname.csx", "-restore", "--", "-port", "--", "8080" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); + Assert.Equal(new string[] { "-port", "--", "8080" }, scriptArgs); + } + + [Fact] + public void ShouldHandleTrailingDoubledash() + { + string[] args = new string[] { "scriptname.csx", "-restore", "--" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); + Assert.Equal(new string[0], scriptArgs); + } + + public class ScriptArgsPlumbing { + [Fact] + public void ScriptArgsArePlumbedThrough() + { + + } + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 6b87c8ea..97db7eeb 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -44,6 +44,7 @@ + From f20f867e30b82340502342747ff535121c5ce7d3 Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Fri, 17 May 2013 16:56:40 -0700 Subject: [PATCH 0265/1224] Additional unit tests. --- src/ScriptCs/Command/ExecuteReplCommand.cs | 2 ++ src/ScriptCs/Command/ExecuteScriptCommand.cs | 7 ++++--- src/ScriptCs/Command/ICommand.cs | 4 +++- test/ScriptCs.Core.Tests/ScriptHostTests.cs | 13 ++++++++++++- test/ScriptCs.Tests/CommandFactoryTests.cs | 17 +++++++++++++++++ 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index e62f767e..76303812 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -20,6 +20,8 @@ internal class ExecuteReplCommand : IScriptCommand private readonly ILog _logger; private readonly IConsole _console; + public string[] ScriptArgs { get; private set; } + public ExecuteReplCommand( IFileSystem fileSystem, IScriptPackResolver scriptPackResolver, diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 391e5a94..6d7b1d38 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -10,7 +10,6 @@ namespace ScriptCs.Command internal class ExecuteScriptCommand : IScriptCommand { private readonly string _script; - private readonly string[] _scriptArgs; private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; @@ -27,7 +26,7 @@ public ExecuteScriptCommand(string script, IAssemblyName assemblyName) { _script = script; - _scriptArgs = scriptArgs; + ScriptArgs = scriptArgs; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; @@ -35,6 +34,8 @@ public ExecuteScriptCommand(string script, _assemblyName = assemblyName; } + public string[] ScriptArgs { get; private set; } + public CommandResult Execute() { try @@ -47,7 +48,7 @@ public CommandResult Execute() assemblyPaths = GetAssemblyPaths(workingDirectory); } - _scriptExecutor.Execute(_script, _scriptArgs, assemblyPaths, _scriptPackResolver.GetPacks()); + _scriptExecutor.Execute(_script, ScriptArgs, assemblyPaths, _scriptPackResolver.GetPacks()); return CommandResult.Success; } catch (Exception ex) diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index ec1477b9..41c55ea3 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -2,7 +2,9 @@ namespace ScriptCs.Command { - public interface IScriptCommand : ICommand { } + public interface IScriptCommand : ICommand { + string[] ScriptArgs { get; } + } public interface IRestoreCommand : ICommand { } diff --git a/test/ScriptCs.Core.Tests/ScriptHostTests.cs b/test/ScriptCs.Core.Tests/ScriptHostTests.cs index 3a80cd59..b2b0c2b0 100644 --- a/test/ScriptCs.Core.Tests/ScriptHostTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptHostTests.cs @@ -29,7 +29,18 @@ public TheGetMethod() public void ShoulGetScriptPackFromScriptPackManagerWhenInvoked() { var result = _scriptHost.Require(); - _mockScriptPackManager.Verify(s=>s.Get()); + _mockScriptPackManager.Verify(s => s.Get()); + } + } + + public class TheConstructor + { + [Fact] + public void ShouldSetScriptArgsWhenConstructed() + { + var scriptArgs = new string[0]; + var scriptHost = new ScriptHost(null, scriptArgs); + scriptHost.ScriptArgs.ShouldEqual(scriptArgs); } } } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index b8be9568..47bb68e7 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -206,6 +206,23 @@ public void ShouldReturnHelpCommandWhenHelpIsPassed() result.ShouldImplement(); } + + [Fact] + public void ShouldPassScriptArgsToExecuteCommandConstructor() + { + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = null, + ScriptName = "test.csx" + }; + + var scriptArgs = new string[0]; + var factory = new CommandFactory(CreateRoot()); + var result = factory.CreateCommand(args, scriptArgs) as IScriptCommand; + + result.ScriptArgs.ShouldEqual(scriptArgs); + } } } } From 30a9ec11ab667bd64a99f45c94fabaf85f227b4f Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 14:07:37 +0200 Subject: [PATCH 0266/1224] moved IConsole to ScriptCs.Contracts --- src/{ScriptCs => ScriptCs.Contracts}/IConsole.cs | 6 +----- src/ScriptCs.Contracts/ScriptCs.Contracts.csproj | 1 + src/ScriptCs/Command/ExecuteReplCommand.cs | 1 + src/ScriptCs/ReplConsole.cs | 1 + src/ScriptCs/ScriptCs.csproj | 1 - src/ScriptCs/ScriptServiceRoot.cs | 1 + test/ScriptCs.Tests/ExecuteReplCommandTests.cs | 1 + 7 files changed, 6 insertions(+), 6 deletions(-) rename src/{ScriptCs => ScriptCs.Contracts}/IConsole.cs (68%) diff --git a/src/ScriptCs/IConsole.cs b/src/ScriptCs.Contracts/IConsole.cs similarity index 68% rename from src/ScriptCs/IConsole.cs rename to src/ScriptCs.Contracts/IConsole.cs index f7935d91..b74bd4d4 100644 --- a/src/ScriptCs/IConsole.cs +++ b/src/ScriptCs.Contracts/IConsole.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace ScriptCs +namespace ScriptCs.Contracts { public interface IConsole { diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 3f667d25..eb9c4496 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -20,6 +20,7 @@ + diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index e62f767e..aca38cf1 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Common.Logging; using System.Reflection; +using ScriptCs.Contracts; namespace ScriptCs.Command { diff --git a/src/ScriptCs/ReplConsole.cs b/src/ScriptCs/ReplConsole.cs index a2eddbcb..1df082ef 100644 --- a/src/ScriptCs/ReplConsole.cs +++ b/src/ScriptCs/ReplConsole.cs @@ -1,4 +1,5 @@ using System; +using ScriptCs.Contracts; namespace ScriptCs { diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 47286cee..6cb6bd9e 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -74,7 +74,6 @@ - diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index cc32788a..ac2c90e7 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -1,4 +1,5 @@ using Common.Logging; +using ScriptCs.Contracts; using ScriptCs.Package; namespace ScriptCs diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index d98de537..e8dbdb73 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -4,6 +4,7 @@ using Common.Logging; using Moq; using ScriptCs.Command; +using ScriptCs.Contracts; using ScriptCs.Package; using Xunit; From 948ee6e314a2d96d262bab13e498bb84aed34b97 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 14:19:49 +0200 Subject: [PATCH 0267/1224] extended IScriptExecutor with Initialize and Terminate, refactored accordingly --- src/ScriptCs.Core/IScriptExecutor.cs | 4 +- src/ScriptCs.Core/ScriptExecutor.cs | 53 +++++++++++-------- src/ScriptCs/Command/ExecuteScriptCommand.cs | 5 +- .../ScriptExecutorTests.cs | 32 +++++++---- .../ExecuteScriptCommandTests.cs | 8 ++- 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/src/ScriptCs.Core/IScriptExecutor.cs b/src/ScriptCs.Core/IScriptExecutor.cs index 07ca8b8f..539f61df 100644 --- a/src/ScriptCs.Core/IScriptExecutor.cs +++ b/src/ScriptCs.Core/IScriptExecutor.cs @@ -5,6 +5,8 @@ namespace ScriptCs { public interface IScriptExecutor { - void Execute(string script, IEnumerable paths, IEnumerable recipes); + void Initialize(IEnumerable paths, IEnumerable scriptPacks); + void Execute(string script); + void Terminate(); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 14641fff..b07ea942 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -8,44 +8,53 @@ namespace ScriptCs { public class ScriptExecutor : IScriptExecutor { - private static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; + public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; - private readonly IFileSystem _fileSystem; - private readonly IFilePreProcessor _filePreProcessor; - private readonly IScriptEngine _scriptEngine; - private readonly ILog _logger; + public IFileSystem FileSystem { get; private set; } + public IFilePreProcessor FilePreProcessor { get; private set; } + public IScriptEngine ScriptEngine { get; private set; } + public ILog Logger { get; private set; } + public IEnumerable References { get; protected set; } + public ScriptPackSession ScriptPackSession { get; protected set; } public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) { - _fileSystem = fileSystem; - _filePreProcessor = filePreProcessor; - _scriptEngine = scriptEngine; - _logger = logger; + FileSystem = fileSystem; + FilePreProcessor = filePreProcessor; + ScriptEngine = scriptEngine; + Logger = logger; } - public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) + public virtual void Initialize(IEnumerable paths, IEnumerable scriptPacks) { - var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); + References = DefaultReferences.Union(paths); + var bin = Path.Combine(FileSystem.CurrentDirectory, "bin"); - _scriptEngine.BaseDirectory = bin; + ScriptEngine.BaseDirectory = bin; - _logger.Debug("Initializing script packs"); + Logger.Debug("Initializing script packs"); var scriptPackSession = new ScriptPackSession(scriptPacks); scriptPackSession.InitializePacks(); + ScriptPackSession = scriptPackSession; - var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); - - var result = _filePreProcessor.ProcessFile(path); + } - var references = DefaultReferences.Union(paths).Union(result.References); + public virtual void Terminate() + { + Logger.Debug("Terminating packs"); + ScriptPackSession.TerminatePacks(); + } - _logger.Debug("Starting execution in engine"); - _scriptEngine.Execute(result.Code, references, DefaultNamespaces, scriptPackSession); + public virtual void Execute(string script) + { + var path = Path.IsPathRooted(script) ? script : Path.Combine(FileSystem.CurrentDirectory, script); + var result = FilePreProcessor.ProcessFile(path); + var references = References.Union(result.References); - _logger.Debug("Terminating packs"); - scriptPackSession.TerminatePacks(); + Logger.Debug("Starting execution in engine"); + ScriptEngine.Execute(result.Code, references, DefaultNamespaces, ScriptPackSession); } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index e60e2ad2..5501b337 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -44,7 +44,10 @@ public CommandResult Execute() assemblyPaths = GetAssemblyPaths(workingDirectory); } - _scriptExecutor.Execute(_script, assemblyPaths, _scriptPackResolver.GetPacks()); + _scriptExecutor.Initialize(assemblyPaths, _scriptPackResolver.GetPacks()); + _scriptExecutor.Execute(_script); + _scriptExecutor.Terminate(); + return CommandResult.Success; } catch (Exception ex) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 0224b23e..13e877de 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -50,7 +50,8 @@ public void ConstructsAbsolutePathBeforePreProcessingFile() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx"); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -65,7 +66,8 @@ public void DoNotChangePathIfAbsolute() preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute(@"c:\my_script\script.csx"); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -92,7 +94,8 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() IEnumerable recipes = Enumerable.Empty(); // act - scriptExecutor.Execute(scriptName, paths, recipes); + scriptExecutor.Initialize(paths, recipes); + scriptExecutor.Execute(scriptName); // assert string expectedBaseDirectory = Path.Combine(currentDirectory, "bin"); @@ -126,7 +129,8 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny())); // act - scriptExecutor.Execute(scriptName, paths, recipes); + scriptExecutor.Initialize(paths, recipes); + scriptExecutor.Execute(scriptName); // assert preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); @@ -165,7 +169,8 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); // act - scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); + scriptExecutor.Initialize(paths, Enumerable.Empty()); + scriptExecutor.Execute(scriptName); // assert scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); @@ -187,7 +192,8 @@ public void ShouldInitializeScriptPacks() scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx"); scriptPack1.Verify(p => p.Initialize(It.IsAny())); } @@ -209,7 +215,9 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); scriptPack1.Setup(p => p.Terminate()); - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx"); + executor.Terminate(); scriptPack1.Verify(p => p.Terminate()); } @@ -217,7 +225,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() [Fact] public void ExecutorShouldPassDefaultNamespacesToEngine() { - var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; + var expectedNamespaces = ScriptExecutor.DefaultNamespaces; var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); @@ -230,7 +238,8 @@ public void ExecutorShouldPassDefaultNamespacesToEngine() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx"); engine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); } @@ -238,7 +247,7 @@ public void ExecutorShouldPassDefaultNamespacesToEngine() [Fact] public void ExecutorShouldPassDefaultReferencesToEngine() { - var defaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + var defaultReferences = ScriptExecutor.DefaultReferences; var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); @@ -251,7 +260,8 @@ public void ExecutorShouldPassDefaultReferencesToEngine() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx"); engine.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Except(defaultReferences).Any()), It.IsAny>(), It.IsAny()), Times.Exactly(1)); } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 55640149..5e504bb4 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -43,7 +43,9 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() result.Execute(); - executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny>(), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Initialize(It.IsAny>(), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx")), Times.Once()); + executor.Verify(i => i.Terminate(), Times.Once()); } [Fact] @@ -115,7 +117,9 @@ public void NonManagedAssembliesAreExcluded() result.Execute(); - executor.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Initialize(It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx")), Times.Once()); + executor.Verify(i => i.Terminate(), Times.Once()); } } } From 93b8713f915018639a6b445fce5253bd4f173d8d Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 14:30:06 +0200 Subject: [PATCH 0268/1224] moved Repl to ScriptCs.Core and derived it from ScriptExecutor to prevent code duplication --- src/{ScriptCs => ScriptCs.Core}/Repl.cs | 39 ++++--------------------- src/ScriptCs.Core/ScriptCs.Core.csproj | 4 +++ src/ScriptCs/ScriptCs.csproj | 4 --- 3 files changed, 9 insertions(+), 38 deletions(-) rename src/{ScriptCs => ScriptCs.Core}/Repl.cs (59%) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs.Core/Repl.cs similarity index 59% rename from src/ScriptCs/Repl.cs rename to src/ScriptCs.Core/Repl.cs index fc38c2df..61f597af 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.IO; using Common.Logging; @@ -8,52 +7,24 @@ namespace ScriptCs { - public class Repl + public class Repl : ScriptExecutor { - public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; - - public IFileSystem FileSystem { get; private set; } - public IScriptEngine ScriptEngine { get; private set; } - public IFilePreProcessor FilePreProcessor { get; private set; } - public ILog Logger { get; private set; } public IConsole Console { get; private set; } - public ScriptPackSession ScriptPackSession { get; private set; } - public IEnumerable References { get; private set; } public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console, IFilePreProcessor filePreProcessor) + : base(fileSystem, filePreProcessor, scriptEngine, logger) { - FileSystem = fileSystem; - ScriptEngine = scriptEngine; - FilePreProcessor = filePreProcessor; - Logger = logger; Console = console; } - public void Initialize(IEnumerable paths, IEnumerable scriptPacks) - { - References = DefaultReferences.Union(paths); - var bin = Path.Combine(FileSystem.CurrentDirectory, "bin"); - - ScriptEngine.BaseDirectory = bin; - - Logger.Debug("Initializing script packs"); - var scriptPackSession = new ScriptPackSession(scriptPacks); - - scriptPackSession.InitializePacks(); - ScriptPackSession = scriptPackSession; - - } - - public void Terminate() + public override void Terminate() { - Logger.Debug("Terminating packs"); - ScriptPackSession.TerminatePacks(); + base.Terminate(); Logger.Debug("Exiting console"); Console.Exit(); } - public void Execute(string script) + public override void Execute(string script) { try { diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index f8f67000..8039e66f 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -29,6 +29,9 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + + ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll + @@ -76,6 +79,7 @@ + diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 6cb6bd9e..d0a48452 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -38,9 +38,6 @@ False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll - - ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll - @@ -76,7 +73,6 @@ - From 35004b80e73d26ca16e52b58cc097a6dc85c288f Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 14:49:14 +0200 Subject: [PATCH 0269/1224] refactored ScriptExecutorTests to reflect the new structure --- .../ScriptExecutorTests.cs | 157 +++++++++--------- 1 file changed, 82 insertions(+), 75 deletions(-) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 13e877de..364d25ec 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -36,27 +36,64 @@ public static ScriptExecutor CreateScriptExecutor( return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, logger.Object); } - public class TheExecuteMethod + public class TheInitializeMethod { [Fact] - public void ConstructsAbsolutePathBeforePreProcessingFile() + public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() + { + // arrange + var scriptEngine = new Mock(); + var fileSystem = new Mock(); + var preProcessor = new Mock(); + preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); + + var currentDirectory = @"C:\"; + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); + fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + + scriptEngine.SetupProperty(e => e.BaseDirectory); + + var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); + + var paths = new string[0]; + IEnumerable recipes = Enumerable.Empty(); + + // act + scriptExecutor.Initialize(paths, recipes); + + // assert + string expectedBaseDirectory = Path.Combine(currentDirectory, "bin"); + expectedBaseDirectory.ShouldEqual(scriptEngine.Object.BaseDirectory); + } + + [Fact] + public void ShouldInitializeScriptPacks() { var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); - executor.Execute("script.csx"); - preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + + // act + executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + + // assert + scriptPack1.Verify(p => p.Initialize(It.IsAny())); } + } + public class TheTerminateMethod + { [Fact] - public void DoNotChangePathIfAbsolute() + public void ShouldTerminateScriptPacksWhenTerminateIsCalled() { var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); @@ -66,40 +103,56 @@ public void DoNotChangePathIfAbsolute() preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); - executor.Execute(@"c:\my_script\script.csx"); - preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + scriptPack1.Setup(p => p.Terminate()); + + // act + executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx"); + executor.Terminate(); + + // assert + scriptPack1.Verify(p => p.Terminate()); } + } + public class TheExecuteMethod + { [Fact] - public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() + public void ConstructsAbsolutePathBeforePreProcessingFile() { - // arrange - var scriptEngine = new Mock(); var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + var preProcessor = new Mock(); - preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var currentDirectory = @"C:\"; - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - scriptEngine.SetupProperty(e => e.BaseDirectory); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx"); + preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); + } - var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); + [Fact] + public void DoNotChangePathIfAbsolute() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var scriptName = "script.csx"; - var paths = new string[0]; - IEnumerable recipes = Enumerable.Empty(); + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - // act - scriptExecutor.Initialize(paths, recipes); - scriptExecutor.Execute(scriptName); + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute(@"c:\my_script\script.csx"); - // assert - string expectedBaseDirectory = Path.Combine(currentDirectory, "bin"); - expectedBaseDirectory.ShouldEqual(scriptEngine.Object.BaseDirectory); + preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } [Fact] @@ -143,7 +196,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut public void ShouldAddReferenceToEachDestinationFile() { // arrange - var defaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + var defaultReferences = ScriptExecutor.DefaultReferences; var fileSystem = new Mock(); var scriptEngine = new Mock(); var preProcessor = new Mock(); @@ -176,52 +229,6 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); } - [Fact] - public void ShouldInitializeScriptPacks() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.Initialize(It.IsAny())); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - - executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); - executor.Execute("script.csx"); - - scriptPack1.Verify(p => p.Initialize(It.IsAny())); - } - - [Fact] - public void ShouldTerminateScriptPacksWhenScriptFinishes() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.Initialize(It.IsAny())); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - scriptPack1.Setup(p => p.Terminate()); - - executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); - executor.Execute("script.csx"); - executor.Terminate(); - - scriptPack1.Verify(p => p.Terminate()); - } - [Fact] public void ExecutorShouldPassDefaultNamespacesToEngine() { From 9369b40c9c7bbdfa15030e90bd88b35843970d69 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 15:35:17 +0200 Subject: [PATCH 0270/1224] added possibility to get full path from filesystem to facilitate #r loading in REPL --- src/ScriptCs.Core/FileSystem.cs | 5 +++++ src/ScriptCs.Core/IFileSystem.cs | 2 ++ src/ScriptCs.Core/Repl.cs | 2 +- test/ScriptCs.Tests/ReplTests.cs | 20 ++++++++++++++++++-- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index d8e0bb25..b60b5bad 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -90,5 +90,10 @@ public string GetWorkingDirectory(string path) { return IsPathRooted(path) ? Path.GetDirectoryName(path) : CurrentDirectory; } + + public string GetFullPath(string path) + { + return Path.GetFullPath(path); + } } } diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 253be305..1d6d7ddf 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -24,6 +24,8 @@ public interface IFileSystem bool IsPathRooted(string path); + string GetFullPath(string path); + string CurrentDirectory { get; } string NewLine { get; } diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 61f597af..8f7ef2ce 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -43,7 +43,7 @@ public override void Execute(string script) } else if (PreProcessorUtil.IsRLine(script)) { - var assemblyPath = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); + var assemblyPath = FileSystem.GetFullPath(Path.Combine(Constants.BinFolder, PreProcessorUtil.GetPath(PreProcessorUtil.RString, script))); if (FileSystem.FileExists(assemblyPath)) { References = References.Union(new[] { assemblyPath }); diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 002a0930..c835ac77 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -216,7 +216,8 @@ public void ShouldReferenceAssemblyIfLineIsAReference() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); - mocks.FileSystem.Setup(x => x.FileExists("my.dll")).Returns(true); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"c:/my.dll"); + mocks.FileSystem.Setup(x => x.FileExists("c:/my.dll")).Returns(true); _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); @@ -231,7 +232,8 @@ public void ShouldNotReferenceAssemblyIfFileDoesNotExist() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); - mocks.FileSystem.Setup(x => x.FileExists("my.dll")).Returns(false); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"c:/my.dll"); + mocks.FileSystem.Setup(x => x.FileExists("c:/my.dll")).Returns(false); _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); @@ -241,6 +243,20 @@ public void ShouldNotReferenceAssemblyIfFileDoesNotExist() _repl.References.Count().ShouldEqual(6); } + [Fact] + public void ShouldReferenceAssemblyBasedOnFullPath() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"C:/my.dll"); + + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"my.dll\""); + + mocks.FileSystem.Verify(x => x.FileExists("C:/my.dll"), Times.Once()); + } + [Fact] public void ShouldNotExecuteAnythingIfLineIsAReference() { From 0f3248e2bbb9c28fefbaa49a1ef769b4d739d28e Mon Sep 17 00:00:00 2001 From: Tim Erickson Date: Thu, 23 May 2013 19:26:39 -0700 Subject: [PATCH 0271/1224] Added ScriptResult.cs and tests --- src/ScriptCs.Core/IScriptEngine.cs | 2 +- src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs.Core/ScriptResult.cs | 13 ++ .../RoslynScriptDebuggerEngine.cs | 27 +++- .../RoslynScriptEngine.cs | 26 +++- .../RoslynScriptEngineTests.cs | 130 +++++++++++++++++- 6 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 src/ScriptCs.Core/ScriptResult.cs diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index 94740e2b..c98108df 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -5,6 +5,6 @@ namespace ScriptCs public interface IScriptEngine { string BaseDirectory { get; set; } - object Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); + ScriptResult Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index f8f67000..685a8f61 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -82,6 +82,7 @@ + diff --git a/src/ScriptCs.Core/ScriptResult.cs b/src/ScriptCs.Core/ScriptResult.cs new file mode 100644 index 00000000..10933f69 --- /dev/null +++ b/src/ScriptCs.Core/ScriptResult.cs @@ -0,0 +1,13 @@ +using System; + +namespace ScriptCs +{ + public class ScriptResult + { + public object ReturnValue { get; set; } + + public Exception ExecuteException { get; set; } + + public Exception CompileException { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index f1043270..0a632339 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -20,12 +20,23 @@ public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory, ILog log this._logger = logger; } - protected override object Execute(string code, Session session) + protected override ScriptResult Execute(string code, Session session) { Guard.AgainstNullArgument("session", session); + var scriptResult = new ScriptResult(); + Submission submission = null; + _logger.Debug("Compiling submission"); - var submission = session.CompileSubmission(code); + try + { + submission = session.CompileSubmission(code); + } + catch (Exception compileException) + { + scriptResult.CompileException = compileException; + } + var exeBytes = new byte[0]; var pdbBytes = new byte[0]; var compileSuccess = false; @@ -61,21 +72,23 @@ protected override object Execute(string code, Session session) try { _logger.Debug("Invoking method."); - return method.Invoke(null, new[] { session }); + scriptResult.ReturnValue = method.Invoke(null, new[] { session }); } - catch (Exception e) + catch (Exception executeException) { + scriptResult.ExecuteException = executeException; _logger.Error("An error occurred when executing the scripts."); var message = string.Format( "Exception Message: {0} {1}Stack Trace:{2}", - e.InnerException.Message, + executeException.InnerException.Message, Environment.NewLine, - e.InnerException.StackTrace); + executeException.InnerException.StackTrace); throw new ScriptExecutionException(message); } } - return null; + + return scriptResult; } } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index e011eb8d..6ae75a46 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using Common.Logging; @@ -28,7 +29,7 @@ public string BaseDirectory set { _scriptEngine.BaseDirectory = value; } } - public object Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) + public ScriptResult Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { Guard.AgainstNullArgument("scriptPackSession", scriptPackSession); @@ -82,11 +83,28 @@ public object Execute(string code, string[] scriptArgs, IEnumerable refe return result; } - protected virtual object Execute(string code, Session session) + protected virtual ScriptResult Execute(string code, Session session) { Guard.AgainstNullArgument("session", session); - return session.Execute(code); + var result = new ScriptResult(); + try + { + var submission = session.CompileSubmission(code); + try + { + result.ReturnValue = submission.Execute(); + } + catch (Exception ex) + { + result.ExecuteException = ex; + } + } + catch (Exception ex) + { + result.CompileException = ex; + } + return result; } } } \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 21780bc6..fc013f64 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -23,10 +23,10 @@ public TestRoslynScriptEngine(IScriptHostFactory scriptHostFactory, ILog logger) public Session Session { get; set; } - protected override object Execute(string code, Session session) + protected override ScriptResult Execute(string code, Session session) { Session = session; - return null; + return new ScriptResult(); } } @@ -119,6 +119,132 @@ public void ShouldAddNewReferencesIfTheyAreProvided() ((SessionState)scriptPackSession.State[RoslynScriptEngine.SessionKey]).References.Count().ShouldEqual(1); } + + [Fact] + public void ShouldReturnAScriptResult() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = ""; + + var engine = CreateTestScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + Assert.IsType(result); + } + + [Fact] + public void ShouldReturnCompileExceptionIfCodeDoesNotCompile() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "this shold not compile"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.CompileException.ShouldNotBeNull(); + } + + [Fact] + public void ShouldNotReturnCompileExceptionIfCodeDoesCompile() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "var theNumber = 42; //this should compile"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.CompileException.ShouldBeNull(); + } + + [Fact] + public void ShouldReturnExecuteExceptionIfCodeExecutionThrowsException() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "throw new System.Exception(); //this should throw an Exception"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.ExecuteException.ShouldNotBeNull(); + } + + [Fact] + public void ShouldNotReturnExecuteExceptionIfCodeExecutionDoesNotThrowAnException() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "var theNumber = 42; //this should not throw an Exception"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.ExecuteException.ShouldBeNull(); + } + + [Fact] + public void ShouldReturnReturnValueIfCodeExecutionReturnsValue() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "\"Hello\" //this should return \"Hello\""; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.ReturnValue.ShouldEqual("Hello"); + } + + [Fact] + public void ShouldNotReturnReturnValueIfCodeExecutionDoesNotReturnValue() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "var theNumber = 42; //this should not return a value"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.ReturnValue.ShouldBeNull(); + } } } } \ No newline at end of file From b252dffdede54784aebe6573321eca0afa6e12cb Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 24 May 2013 13:12:22 +0200 Subject: [PATCH 0272/1224] Fixed wrong argument passed from CommandFactory to RestoreCommand. Fixes #298 --- src/ScriptCs/Command/CommandFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 0a540e5b..d08edacb 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -56,7 +56,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.Logger); var restoreCommand = new RestoreCommand( - args.Install, + args.ScriptName, _scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Logger); From 8fb34deaf73405da111162536c003fbc307064df Mon Sep 17 00:00:00 2001 From: lbargaoanu Date: Fri, 24 May 2013 16:03:51 +0300 Subject: [PATCH 0273/1224] Add logic to grab the delta of binaries if there are changes in the installed packages Fix for https://github.com/scriptcs/scriptcs/issues/2 --- .../IInstallationProvider.cs | 1 + .../NugetInstallationProvider.cs | 35 +++++++++++-------- src/ScriptCs.Core/Package/PackageInstaller.cs | 16 +++++++-- .../PackageInstallerTests.cs | 21 +++++++++++ 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs index 525de7f9..5d8fe5c9 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs @@ -6,6 +6,7 @@ namespace ScriptCs.Package.InstallationProvider public interface IInstallationProvider { IEnumerable GetRepositorySources(string path); + bool IsInstalled(IPackageReference packageId, bool allowPreRelease = false); bool InstallPackage(IPackageReference packageId, bool allowPreRelease = false, Action packageInstalled = null); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index 930554b7..1edb0dc8 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -12,6 +12,8 @@ public class NugetInstallationProvider : IInstallationProvider private readonly PackageManager _manager; private readonly IEnumerable _repositoryUrls; + private static readonly Version EmptyVersion = new Version(); + public NugetInstallationProvider(IFileSystem fileSystem) { Guard.AgainstNullArgument("fileSystem", fileSystem); @@ -51,34 +53,39 @@ public bool InstallPackage(IPackageReference packageId, bool allowPreRelease = f { Guard.AgainstNullArgument("packageId", packageId); - var useVersion = packageId.Version.CompareTo(new Version()) != 0; + var version = GetVersion(packageId); + var packageName = packageId.PackageId + " " + (version == null ? string.Empty : packageId.Version.ToString()); try { - if (useVersion) - { - _manager.InstallPackage(packageId.PackageId, - new SemanticVersion(packageId.Version, packageId.SpecialVersion), false, - allowPreRelease); - } - else + _manager.InstallPackage(packageId.PackageId, version, allowPrereleaseVersions: allowPreRelease, ignoreDependencies: false); + if(packageInstalled != null) { - _manager.InstallPackage(packageId.PackageId, null, false, allowPreRelease); + packageInstalled("Installed: " + packageName); } - - if (packageInstalled != null) - packageInstalled("Installed: " + packageId.PackageId + " " + (useVersion ? packageId.Version.ToString() : "")); - return true; } catch (Exception e) { if (packageInstalled != null) { - packageInstalled("Installation failed: " + packageId.PackageId + " " + (useVersion ? packageId.Version.ToString() : "")); + packageInstalled("Installation failed: " + packageName); packageInstalled(e.Message); } return false; } } + + private static SemanticVersion GetVersion(IPackageReference packageReference) + { + return packageReference.Version == EmptyVersion ? null : new SemanticVersion(packageReference.Version, packageReference.SpecialVersion); + } + + public bool IsInstalled(IPackageReference packageReference, bool allowPreRelease = false) + { + Guard.AgainstNullArgument("packageReference", packageReference); + + var version = GetVersion(packageReference); + return _manager.LocalRepository.FindPackage(packageReference.PackageId, version, allowPreRelease, allowUnlisted: false) != null; + } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/PackageInstaller.cs b/src/ScriptCs.Core/Package/PackageInstaller.cs index d751b925..0bfe646a 100644 --- a/src/ScriptCs.Core/Package/PackageInstaller.cs +++ b/src/ScriptCs.Core/Package/PackageInstaller.cs @@ -29,9 +29,19 @@ public void InstallPackages(IEnumerable packageIds, bool allo return; } - var successful = packageIds.Select(packageId => _installer.InstallPackage(packageId, allowPreRelease, packageInstalled)) - .Aggregate(true, (current, result) => current && result); - + bool successful = true; + foreach(var packageId in packageIds) + { + if(_installer.IsInstalled(packageId, allowPreRelease)) + { + continue; + } + if(!_installer.InstallPackage(packageId, allowPreRelease, packageInstalled)) + { + successful = false; + } + } + if (packageInstalled != null && packageIds.Count() > 1) { packageInstalled(successful ? "Installation successful." : "Installation unsuccessful."); diff --git a/test/ScriptCs.Core.Tests/PackageInstallerTests.cs b/test/ScriptCs.Core.Tests/PackageInstallerTests.cs index dd18ab8a..1cebe925 100644 --- a/test/ScriptCs.Core.Tests/PackageInstallerTests.cs +++ b/test/ScriptCs.Core.Tests/PackageInstallerTests.cs @@ -90,6 +90,27 @@ public void ShouldShowSuccessIfNoneOfPackagesFail() callbacks.Count.ShouldEqual(1); callbacks.Count(x => x.EndsWith("successful.")).ShouldEqual(1); } + + [Fact] + public void ShouldNotInstallExistingPackages() + { + var callbacks = new List(); + var provider = new Mock(); + provider.Setup( + i => i.IsInstalled(It.Is(x => x.PackageId == "testId"), It.IsAny())) + .Returns(true); + + var references = new List { + new PackageReference("testId", VersionUtility.ParseFrameworkName("net40"), new Version("3.0")), + new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"), new Version("4.0")), + new PackageReference("testId3", VersionUtility.ParseFrameworkName("net40"), new Version("5.0")) + }; + + var installer = new PackageInstaller(provider.Object); + installer.InstallPackages(references); + + provider.Verify(i => i.InstallPackage(It.Is(x => x.PackageId == "testId"), It.IsAny(), It.IsAny>()), Times.Never()); + } } } } \ No newline at end of file From f9107cf40f4674739cdc1f84402840635424441e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 14:13:40 +0200 Subject: [PATCH 0274/1224] Removed RestoreCommand --- src/ScriptCs/Command/CommandFactory.cs | 29 +---- src/ScriptCs/Command/ICommand.cs | 2 - src/ScriptCs/Command/RestoreCommand.cs | 72 ----------- src/ScriptCs/ScriptCs.csproj | 1 - src/ScriptCs/ScriptCsArgs.cs | 4 - test/ScriptCs.Tests/CommandFactoryTests.cs | 35 +----- test/ScriptCs.Tests/RestoreCommandTests.cs | 136 --------------------- test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 - 8 files changed, 9 insertions(+), 271 deletions(-) delete mode 100644 src/ScriptCs/Command/RestoreCommand.cs delete mode 100644 test/ScriptCs.Tests/RestoreCommandTests.cs diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d08edacb..d18eb06a 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -55,24 +55,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.PackageInstaller, _scriptServiceRoot.Logger); - var restoreCommand = new RestoreCommand( - args.ScriptName, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.Logger); - - return new CompositeCommand(installCommand, restoreCommand, executeCommand); - } - - if (args.Restore) - { - var restoreCommand = new RestoreCommand( - args.ScriptName, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.Logger); - - return new CompositeCommand(restoreCommand, executeCommand); + return new CompositeCommand(installCommand, executeCommand); } return executeCommand; @@ -88,22 +71,16 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.PackageInstaller, _scriptServiceRoot.Logger); - var restoreCommand = new RestoreCommand( - args.Install, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.Logger); - var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); if (!_scriptServiceRoot.FileSystem.FileExists(packageFile)) { var saveCommand = new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); - return new CompositeCommand(installCommand, restoreCommand, saveCommand); + return new CompositeCommand(installCommand, saveCommand); } - return new CompositeCommand(installCommand, restoreCommand); + return installCommand; } if (args.Clean) diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index 41c55ea3..deef3623 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -6,8 +6,6 @@ public interface IScriptCommand : ICommand { string[] ScriptArgs { get; } } - public interface IRestoreCommand : ICommand { } - public interface ISaveCommand : ICommand { } public interface ICleanCommand : ICommand { } diff --git a/src/ScriptCs/Command/RestoreCommand.cs b/src/ScriptCs/Command/RestoreCommand.cs deleted file mode 100644 index 6f6b155b..00000000 --- a/src/ScriptCs/Command/RestoreCommand.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.IO; -using Common.Logging; - -namespace ScriptCs.Command -{ - internal class RestoreCommand : IRestoreCommand - { - private readonly string _scriptName; - private readonly IFileSystem _fileSystem; - private readonly IPackageAssemblyResolver _packageAssemblyResolver; - - private readonly ILog _logger; - - public RestoreCommand(string scriptName, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, ILog logger) - { - _scriptName = scriptName; - _fileSystem = fileSystem; - _packageAssemblyResolver = packageAssemblyResolver; - _logger = logger; - } - - public CommandResult Execute() - { - _logger.Info("Copying assemblies to bin folder..."); - - var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); - var binFolder = Path.Combine(workingDirectory, Constants.BinFolder); - - try - { - if (!_fileSystem.DirectoryExists(binFolder)) - _fileSystem.CreateDirectory(binFolder); - - var packages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); - foreach (var package in packages) - { - CopyFile(package, binFolder); - } - - _logger.Info("Restore completed successfully."); - return CommandResult.Success; - } - catch (Exception e) - { - _logger.ErrorFormat("Restore failed: {0}.", e.Message); - return CommandResult.Error; - } - } - - private void CopyFile(string package, string binFolder) - { - var assemblyFileName = Path.GetFileName(package); - if (assemblyFileName == null) return; - - var destFile = Path.Combine(binFolder, assemblyFileName); - - var sourceFileLastWriteTime = _fileSystem.GetLastWriteTime(package); - var destFileLastWriteTime = _fileSystem.GetLastWriteTime(destFile); - - if (sourceFileLastWriteTime == destFileLastWriteTime) - { - _logger.InfoFormat("Skipped: {0}.", assemblyFileName); - return; - } - - _fileSystem.Copy(package, destFile, true); - - _logger.InfoFormat("Copied: {0}.", assemblyFileName); - } - } -} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 47286cee..b2605a4d 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -71,7 +71,6 @@ - diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index fd0440aa..0b75acee 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -34,10 +34,6 @@ public class ScriptCsArgs [ArgDescription("Installs and restores packages which are specified in packages.config")] public string Install { get; set; } - [ArgShortcut("restore")] - [ArgDescription("Restores installed packages, making them ready for using by the script")] - public bool Restore { get; set; } - [ArgShortcut("save")] [ArgDescription("Creates a packages.config file based on the packages directory")] public bool Save { get; set; } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 47bb68e7..a12b0857 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -48,16 +48,11 @@ public void ShouldInstallAndRestoreWhenInstallFlagIsOn() var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args, new string[0]); - var compositeCommand = result as ICompositeCommand; - compositeCommand.ShouldNotBeNull(); - - compositeCommand.Commands.Count.ShouldEqual(2); - compositeCommand.Commands[0].ShouldImplement(); - compositeCommand.Commands[1].ShouldImplement(); + result.ShouldImplement(); } [Fact] - public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExists() + public void ShouldInstallAndSaveWhenInstallFlagIsOnAndNoPackagesFileExists() { var args = new ScriptCsArgs { @@ -72,10 +67,9 @@ public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExist var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - compositeCommand.Commands.Count.ShouldEqual(3); + compositeCommand.Commands.Count.ShouldEqual(2); compositeCommand.Commands[0].ShouldImplement(); - compositeCommand.Commands[1].ShouldImplement(); - compositeCommand.Commands[2].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); } [Fact] @@ -111,10 +105,9 @@ public void ShouldInstallAndExecuteWhenScriptNameIsPassedAndPackagesFolderDoesNo var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - compositeCommand.Commands.Count.ShouldEqual(3); + compositeCommand.Commands.Count.ShouldEqual(1); compositeCommand.Commands[0].ShouldImplement(); - compositeCommand.Commands[1].ShouldImplement(); - compositeCommand.Commands[2].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); } [Fact] @@ -133,22 +126,6 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() result.ShouldImplement(); } - [Fact] - public void ShouldRestoreWhenBothNameAndRestoreArePassed() - { - var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; - - var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args, new string[0]); - - var compositeCommand = result as ICompositeCommand; - compositeCommand.ShouldNotBeNull(); - - compositeCommand.Commands.Count.ShouldEqual(2); - compositeCommand.Commands[0].ShouldImplement(); - compositeCommand.Commands[1].ShouldImplement(); - } - [Fact] public void ShouldSaveAndCleanWhenCleanFlagIsPassed() { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs deleted file mode 100644 index 7ee7559a..00000000 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System; -using System.IO; -using Common.Logging; -using Moq; -using ScriptCs.Command; -using ScriptCs.Package; -using Xunit; - -namespace ScriptCs.Tests -{ - public class RestoreCommandTests - { - public class TheExecuteMethod - { - [Fact] - public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBin() - { - var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - const string CurrentDirectory = @"C:\"; - - var sourceFilePath = Path.Combine(CurrentDirectory, "fileName.cs"); - var sourceWriteTime = new DateTime(2013, 3, 7); - - var destFilePath = Path.Combine(CurrentDirectory, "bin", "fileName.cs"); - var destWriteTime = sourceWriteTime; - - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - - fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); - fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); - - resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(x => x.Copy(sourceFilePath, destFilePath, true), Times.Never()); - fs.Verify(x => x.GetLastWriteTime(sourceFilePath), Times.Once()); - fs.Verify(x => x.GetLastWriteTime(destFilePath), Times.Once()); - } - - [Fact] - public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() - { - var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - const string CurrentDirectory = @"C:\"; - - var sourceFilePath = Path.Combine(CurrentDirectory, "fileName.cs"); - var sourceWriteTime = new DateTime(2013, 3, 7); - - var destFilePath = Path.Combine(CurrentDirectory, "bin", "fileName.cs"); - var destWriteTime = new DateTime(2013, 2, 7); - - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - - fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); - fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); - - resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(x => x.Copy(sourceFilePath, destFilePath, true), Times.Once()); - fs.Verify(x => x.GetLastWriteTime(sourceFilePath), Times.Once()); - fs.Verify(x => x.GetLastWriteTime(destFilePath), Times.Once()); - } - - [Fact] - public void ShouldCreateBinFolderIfItDoesNotExist() - { - var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - const string CurrentDirectory = @"C:\"; - const string BinFolder = @"C:\bin"; - - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - - var binFolderCreated = false; - - fs.Setup(x => x.DirectoryExists(BinFolder)).Returns(() => binFolderCreated).Verifiable(); - fs.Setup(x => x.CreateDirectory(BinFolder)).Callback(() => binFolderCreated = true).Verifiable(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(x => x.DirectoryExists(BinFolder), Times.AtLeastOnce()); - fs.Verify(x => x.CreateDirectory(BinFolder), Times.Once()); - } - } - } -} diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 97db7eeb..5b33244c 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -48,7 +48,6 @@ - From f85575727037cc5d10945fa6ae5ecbca81f561b2 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 14:14:49 +0200 Subject: [PATCH 0275/1224] Fixed failing test --- test/ScriptCs.Tests/CommandFactoryTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index a12b0857..cc8247dd 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -105,7 +105,7 @@ public void ShouldInstallAndExecuteWhenScriptNameIsPassedAndPackagesFolderDoesNo var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - compositeCommand.Commands.Count.ShouldEqual(1); + compositeCommand.Commands.Count.ShouldEqual(2); compositeCommand.Commands[0].ShouldImplement(); compositeCommand.Commands[1].ShouldImplement(); } From f1dccbfecff58ca90453d4d5197c7fcb17df37aa Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 14:18:25 +0200 Subject: [PATCH 0276/1224] Removed bin folder logic in CleanCommand --- src/ScriptCs/Command/CleanCommand.cs | 43 +----------- src/ScriptCs/Command/CommandFactory.cs | 1 - test/ScriptCs.Tests/CleanCommandTests.cs | 87 +----------------------- 3 files changed, 4 insertions(+), 127 deletions(-) diff --git a/src/ScriptCs/Command/CleanCommand.cs b/src/ScriptCs/Command/CleanCommand.cs index 62b62173..dcbc4d22 100644 --- a/src/ScriptCs/Command/CleanCommand.cs +++ b/src/ScriptCs/Command/CleanCommand.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using Common.Logging; namespace ScriptCs.Command @@ -8,17 +7,15 @@ namespace ScriptCs.Command internal class CleanCommand : ICleanCommand { private readonly string _scriptName; + private readonly IFileSystem _fileSystem; - private readonly IPackageAssemblyResolver _packageAssemblyResolver; + private readonly ILog _logger; - public CleanCommand(string scriptName, - IFileSystem fileSystem, - IPackageAssemblyResolver packageAssemblyResolver, ILog logger) + public CleanCommand(string scriptName, IFileSystem fileSystem, ILog logger) { _scriptName = scriptName; _fileSystem = fileSystem; - _packageAssemblyResolver = packageAssemblyResolver; _logger = logger; } @@ -29,32 +26,11 @@ public CommandResult Execute() var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); _logger.TraceFormat("Working directory: {0}", workingDirectory); - var binFolder = Path.Combine(workingDirectory, Constants.BinFolder); - _logger.TraceFormat("Bin folder: {0}", binFolder); - var packageFolder = Path.Combine(workingDirectory, Constants.PackagesFolder); _logger.TraceFormat("Packages folder: {0}", packageFolder); try { - if (_fileSystem.DirectoryExists(binFolder)) - { - var packages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); - - foreach (var package in packages) - { - _logger.DebugFormat("Deleting file: {0}", package); - DeleteFile(package, binFolder); - } - - var remaining = _fileSystem.EnumerateFiles(binFolder, "*.*").Any(); - if (!remaining) - { - _logger.DebugFormat("Deleting bin directory: {0}", binFolder); - _fileSystem.DeleteDirectory(binFolder); - } - } - if (_fileSystem.DirectoryExists(packageFolder)) { _logger.DebugFormat("Deleting package directory: {0}", packageFolder); @@ -70,18 +46,5 @@ public CommandResult Execute() return CommandResult.Error; } } - - private void DeleteFile(string package, string binFolder) - { - var assemblyFileName = Path.GetFileName(package); - if (assemblyFileName == null) return; - - var destFile = Path.Combine(binFolder, assemblyFileName); - - if (_fileSystem.FileExists(destFile)) - { - _fileSystem.FileDelete(destFile); - } - } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d18eb06a..08326c98 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -90,7 +90,6 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) var cleanCommand = new CleanCommand( args.ScriptName, _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Logger); return new CompositeCommand(saveCommand, cleanCommand); diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index cae08c14..b4526fcd 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,5 +1,4 @@ -using System; -using Common.Logging; +using Common.Logging; using Moq; using ScriptCs.Command; using ScriptCs.Package; @@ -38,90 +37,6 @@ public void ShouldDeletePackagesFolder() fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); } - - [Fact] - public void ShouldDeleteBinFolder() - { - var args = new ScriptCsArgs { Clean = true }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - } - - [Fact] - public void ShouldNotDeleteBinFolderIfDllsAreLeft() - { - var args = new ScriptCsArgs { Clean = true }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); - fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); - } - - [Fact] - public void ShouldDeleteAllFilesResolvedFromPackages() - { - var args = new ScriptCsArgs { Clean = true }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); - resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); - } } } } From 1b3ad3ac36ebd4accd8d19a0db1f136e96a9bce3 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 14:22:05 +0200 Subject: [PATCH 0277/1224] Added SearchOption parameter to FileSystem.EnumerateFiles --- src/ScriptCs.Core/FileSystem.cs | 4 ++-- src/ScriptCs.Core/IFileSystem.cs | 2 +- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index d8e0bb25..53de46b8 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -6,9 +6,9 @@ namespace ScriptCs { public class FileSystem : IFileSystem { - public IEnumerable EnumerateFiles(string dir, string searchPattern) + public IEnumerable EnumerateFiles(string dir, string searchPattern, SearchOption searchOption = SearchOption.AllDirectories) { - return Directory.EnumerateFiles(dir, searchPattern, SearchOption.AllDirectories); + return Directory.EnumerateFiles(dir, searchPattern, searchOption); } public void Copy(string source, string dest, bool overwrite) diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 253be305..e08db619 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -6,7 +6,7 @@ namespace ScriptCs { public interface IFileSystem { - IEnumerable EnumerateFiles(string dir, string search); + IEnumerable EnumerateFiles(string dir, string search, SearchOption searchOption = SearchOption.AllDirectories); void Copy(string source, string dest, bool overwrite); diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 453393b1..5c97be8a 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -92,7 +92,7 @@ public void NonManagedAssembliesAreExcluded() var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { + fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(new[] { "managed.dll", nonManaged }); From ecb33fb7ec4eb748ee01e34beee8cd5595138793 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 21:19:22 +0200 Subject: [PATCH 0278/1224] Changed registering of MEF composable part catalog --- src/ScriptCs/CompositionRoot.cs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 94d36a7f..3a0faf91 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -1,6 +1,8 @@ using System; using System.ComponentModel.Composition.Hosting; using System.IO; +using System.Linq; + using Autofac; using Autofac.Integration.Mef; using Common.Logging; @@ -66,16 +68,20 @@ public void Initialize() builder.RegisterType().As(); - if (_shouldInitDrirectoryCatalog) + if (_shouldInitDrirectoryCatalog) { - var scriptPath = Path.Combine(Environment.CurrentDirectory, "bin"); - if (Directory.Exists(scriptPath)) - { - var catalog = new DirectoryCatalog(scriptPath); - builder.RegisterComposablePartCatalog(catalog); - } + var directory = Environment.CurrentDirectory; + + var directoryCatalogs = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories) + .Union(Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)) + .Select(Path.GetDirectoryName).Distinct() + .Select(x => new DirectoryCatalog(x)); + + builder.RegisterComposablePartCatalog(new AggregateCatalog(directoryCatalogs)); } + _container = builder.Build(); + _scriptServiceRoot = _container.Resolve(); } From 624c6bc53913dddb3268f027a19cf304f2bc05d9 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 21:20:20 +0200 Subject: [PATCH 0279/1224] Added common base class for ExecuteScript- and ExecuteReplCommand --- src/ScriptCs/Command/CommandFactory.cs | 11 ++- src/ScriptCs/Command/ExecuteReplCommand.cs | 81 +++++-------------- src/ScriptCs/Command/ExecuteScriptCommand.cs | 57 ++----------- src/ScriptCs/Command/ScriptCommand.cs | 74 +++++++++++++++++ src/ScriptCs/ScriptCs.csproj | 1 + .../ExecuteScriptCommandTests.cs | 32 -------- 6 files changed, 108 insertions(+), 148 deletions(-) create mode 100644 src/ScriptCs/Command/ScriptCommand.cs diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 08326c98..d95970ef 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -23,9 +23,15 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Repl) { var replCommand = new ExecuteReplCommand( - _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.ScriptPackResolver, + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.Engine, + _scriptServiceRoot.FilePreProcessor, + _scriptServiceRoot.Logger, + _scriptServiceRoot.Console, _scriptServiceRoot.AssemblyName); + return replCommand; } @@ -37,6 +43,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, + _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Logger, _scriptServiceRoot.AssemblyName); diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 76303812..62538c4e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -1,62 +1,52 @@ using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + using Common.Logging; -using System.Reflection; namespace ScriptCs.Command { - internal class ExecuteReplCommand : IScriptCommand + internal class ExecuteReplCommand : ScriptCommand { - private readonly IFileSystem _fileSystem; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssemblyName _assemblyName; - - private readonly ILog _logger; + private readonly IScriptEngine _scriptEngine; private readonly IConsole _console; - public string[] ScriptArgs { get; private set; } - public ExecuteReplCommand( IFileSystem fileSystem, IScriptPackResolver scriptPackResolver, + IPackageAssemblyResolver packageAssemblyResolver, IScriptEngine scriptEngine, IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssemblyName assemblyName - ) + IAssemblyName assemblyName) : base(fileSystem, packageAssemblyResolver, assemblyName, logger) { - _fileSystem = fileSystem; _scriptPackResolver = scriptPackResolver; _scriptEngine = scriptEngine; _filePreProcessor = filePreProcessor; - _logger = logger; _console = console; - _assemblyName = assemblyName; } - public CommandResult Execute() + public override CommandResult Execute() { _console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); - var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console, _filePreProcessor); - repl.Initialize(GetAssemblyPaths(_fileSystem.CurrentDirectory), _scriptPackResolver.GetPacks()); + var repl = new Repl(FileSystem, _scriptEngine, Logger, _console, _filePreProcessor); + + var assemblies = GetAssemblyPaths(FileSystem.CurrentDirectory); + var scriptPacks = _scriptPackResolver.GetPacks(); + + repl.Initialize(assemblies, scriptPacks); + try { - while (ExecuteLine(repl)) - { - } + while (ExecuteLine(repl)) { } } catch (Exception ex) { - _logger.Error(ex.Message); + Logger.Error(ex.Message); return CommandResult.Error; } + repl.Terminate(); return CommandResult.Success; } @@ -64,47 +54,12 @@ public CommandResult Execute() private bool ExecuteLine(Repl repl) { _console.Write("> "); + var line = _console.ReadLine(); - if (line == "") - return false; + if (line == string.Empty) return false; repl.Execute(line); return true; } - - - private IEnumerable GetAssemblyPaths(string workingDirectory) - { - var binFolder = Path.Combine(workingDirectory, "bin"); - - if (!_fileSystem.DirectoryExists(binFolder)) - _fileSystem.CreateDirectory(binFolder); - - var assemblyPaths = - _fileSystem.EnumerateFiles(binFolder, "*.dll") - .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) - .Where(IsManagedAssembly) - .ToList(); - - foreach (var path in assemblyPaths.Select(Path.GetFileName)) - { - _logger.DebugFormat("Found assembly reference: {0}", path); - } - - return assemblyPaths; - } - - private bool IsManagedAssembly(string path) - { - try - { - _assemblyName.GetAssemblyName(path); - } - catch (BadImageFormatException) - { - return false; - } - return true; - } } } diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 6d7b1d38..3380eb41 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -1,48 +1,37 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Linq; using Common.Logging; -using System.Reflection; namespace ScriptCs.Command { - internal class ExecuteScriptCommand : IScriptCommand + internal class ExecuteScriptCommand : ScriptCommand { private readonly string _script; - private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssemblyName _assemblyName; - - private readonly ILog _logger; public ExecuteScriptCommand(string script, string[] scriptArgs, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, + IPackageAssemblyResolver packageAssemblyResolver, ILog logger, - IAssemblyName assemblyName) + IAssemblyName assemblyName) : base(fileSystem, packageAssemblyResolver, assemblyName, logger) { _script = script; ScriptArgs = scriptArgs; - _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; - _logger = logger; - _assemblyName = assemblyName; } - public string[] ScriptArgs { get; private set; } - - public CommandResult Execute() + public override CommandResult Execute() { try { var assemblyPaths = Enumerable.Empty(); - var workingDirectory = _fileSystem.GetWorkingDirectory(_script); + var workingDirectory = FileSystem.GetWorkingDirectory(_script); if (workingDirectory != null) { assemblyPaths = GetAssemblyPaths(workingDirectory); @@ -53,43 +42,9 @@ public CommandResult Execute() } catch (Exception ex) { - _logger.Error(ex.Message); + Logger.Error(ex.Message); return CommandResult.Error; } } - - private IEnumerable GetAssemblyPaths(string workingDirectory) - { - var binFolder = Path.Combine(workingDirectory, "bin"); - - if (!_fileSystem.DirectoryExists(binFolder)) - _fileSystem.CreateDirectory(binFolder); - - var assemblyPaths = - _fileSystem.EnumerateFiles(binFolder, "*.dll") - .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) - .Where(IsManagedAssembly) - .ToList(); - - foreach (var path in assemblyPaths.Select(Path.GetFileName)) - { - _logger.DebugFormat("Found assembly reference: {0}", path); - } - - return assemblyPaths; - } - - private bool IsManagedAssembly(string path) - { - try - { - _assemblyName.GetAssemblyName(path); - } - catch (BadImageFormatException) - { - return false; - } - return true; - } } } diff --git a/src/ScriptCs/Command/ScriptCommand.cs b/src/ScriptCs/Command/ScriptCommand.cs new file mode 100644 index 00000000..32fef83a --- /dev/null +++ b/src/ScriptCs/Command/ScriptCommand.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Common.Logging; + +namespace ScriptCs.Command +{ + public abstract class ScriptCommand : IScriptCommand + { + protected readonly IFileSystem FileSystem; + + protected readonly ILog Logger; + + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + + private readonly IAssemblyName _assemblyName; + + protected ScriptCommand( + IFileSystem fileSystem, + IPackageAssemblyResolver packageAssemblyResolver, + IAssemblyName assemblyName, + ILog logger) + { + FileSystem = fileSystem; + _packageAssemblyResolver = packageAssemblyResolver; + _assemblyName = assemblyName; + Logger = logger; + } + + public string[] ScriptArgs { get; protected set; } + + public abstract CommandResult Execute(); + + protected IEnumerable GetAssemblyPaths(string workingDirectory) + { + var assemblyPaths = new List(); + + var packagesFolder = Path.Combine(workingDirectory, Constants.PackagesFolder); + if (FileSystem.DirectoryExists(packagesFolder)) + { + var packageAssemblies = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); + assemblyPaths.AddRange(packageAssemblies); + } + + var looseAssemblies = FileSystem.EnumerateFiles(workingDirectory, "*.dll", SearchOption.TopDirectoryOnly) + .Union(FileSystem.EnumerateFiles(workingDirectory, "*.exe", SearchOption.TopDirectoryOnly)) + .Where(IsManagedAssembly); + + assemblyPaths.AddRange(looseAssemblies); + + foreach (var path in assemblyPaths) + { + Logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(path)); + } + + return assemblyPaths; + } + + private bool IsManagedAssembly(string path) + { + try + { + _assemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index b2605a4d..a3cb5465 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -66,6 +66,7 @@ + diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 5c97be8a..694a1c1c 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -46,38 +46,6 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny(), It.IsAny>(), It.IsAny>()), Times.Once()); } - [Fact] - public void ShouldCreateMissingBinFolder() - { - const string WorkingDirectory = @"C:\"; - - var binFolder = Path.Combine(WorkingDirectory, "bin"); - - var args = new ScriptCsArgs { ScriptName = "test.csx" }; - - var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(WorkingDirectory); - fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); - - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(x => x.CreateDirectory(binFolder), Times.Once()); - } - [Fact] public void NonManagedAssembliesAreExcluded() { From 83f21b5d38dad943286873bf94de81d143e65b5e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 21:23:33 +0200 Subject: [PATCH 0280/1224] Added variable --- src/ScriptCs/CompositionRoot.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 3a0faf91..dbb50cad 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -72,8 +72,10 @@ public void Initialize() { var directory = Environment.CurrentDirectory; - var directoryCatalogs = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories) - .Union(Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)) + var assemblies = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories) + .Union(Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)); + + var directoryCatalogs = assemblies .Select(Path.GetDirectoryName).Distinct() .Select(x => new DirectoryCatalog(x)); From 13a17497dd8d2c881aa1535ccf1808b74f57ed6f Mon Sep 17 00:00:00 2001 From: SpikeTheMaster Date: Mon, 27 May 2013 12:24:31 +0100 Subject: [PATCH 0281/1224] Fixes #296 - Assembly reference missing with .. * Wrote unit test to prove failing path resolution * Implemented change suggested by @khellang (Use `GetFullPath`) --- src/ScriptCs.Core/FileSystem.cs | 2 +- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index b60b5bad..9ad83afa 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -88,7 +88,7 @@ public Stream CreateFileStream(string filePath, FileMode mode) public string GetWorkingDirectory(string path) { - return IsPathRooted(path) ? Path.GetDirectoryName(path) : CurrentDirectory; + return GetFullPath(path); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index a9eecca7..dc9065f2 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -155,6 +155,14 @@ public void DoNotChangePathIfAbsolute() preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } + [Fact] + public void ShouldResolveAssemblyReferencesCorrectlyWhenNotRunFromCSXFolder() + { + var fileSystem = new FileSystem(); + + Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory,@"..\my_script")), fileSystem.GetWorkingDirectory(@"..\my_script")); + } + [Fact] public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked() { From 14348b4b36de4160aab3bc1bdb1b01ec0037dee2 Mon Sep 17 00:00:00 2001 From: SpikeTheMaster Date: Mon, 27 May 2013 12:54:27 +0100 Subject: [PATCH 0282/1224] Refs #296 - Ensure that the method returns a directory path Ensure that the method returns a directory path and not a file path. Requires that the path have a trailing slash to indicate that it is a directory. Not really sure how to avoid this? --- src/ScriptCs.Core/FileSystem.cs | 4 +++- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 9ad83afa..bc503b7f 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -88,7 +88,9 @@ public Stream CreateFileStream(string filePath, FileMode mode) public string GetWorkingDirectory(string path) { - return GetFullPath(path); + var realPath = GetFullPath(path); + + return Path.GetFileName(realPath) == string.Empty ? realPath : Path.GetDirectoryName(realPath); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index dc9065f2..1b26fbf3 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -160,7 +160,7 @@ public void ShouldResolveAssemblyReferencesCorrectlyWhenNotRunFromCSXFolder() { var fileSystem = new FileSystem(); - Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory,@"..\my_script")), fileSystem.GetWorkingDirectory(@"..\my_script")); + Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory,@"..\my_script\")), fileSystem.GetWorkingDirectory(@"..\my_script\")); } [Fact] From c8df9c99d928f61849d2cdc2b0c93cb9d3f9b66d Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 27 May 2013 17:03:07 +0200 Subject: [PATCH 0283/1224] Removed ScriptCommand base class and renamed IAssemblyName to IAssemblyResolver --- src/ScriptCs.Core/AssemblyName.cs | 10 --- src/ScriptCs.Core/AssemblyResolver.cs | 65 ++++++++++++++++ src/ScriptCs.Core/IAssemblyName.cs | 7 -- src/ScriptCs.Core/IAssemblyResolver.cs | 9 +++ src/ScriptCs.Core/ScriptCs.Core.csproj | 4 +- src/ScriptCs/Command/CommandFactory.cs | 6 +- src/ScriptCs/Command/ExecuteReplCommand.cs | 28 +++++-- src/ScriptCs/Command/ExecuteScriptCommand.cs | 30 +++++--- src/ScriptCs/Command/ScriptCommand.cs | 74 ------------------- src/ScriptCs/CompositionRoot.cs | 2 +- src/ScriptCs/ScriptCs.csproj | 1 - src/ScriptCs/ScriptServiceRoot.cs | 6 +- test/ScriptCs.Tests/CleanCommandTests.cs | 2 +- test/ScriptCs.Tests/CommandFactoryTests.cs | 2 +- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 2 +- .../ExecuteScriptCommandTests.cs | 6 +- test/ScriptCs.Tests/InstallCommandTests.cs | 4 +- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 18 files changed, 132 insertions(+), 128 deletions(-) delete mode 100644 src/ScriptCs.Core/AssemblyName.cs create mode 100644 src/ScriptCs.Core/AssemblyResolver.cs delete mode 100644 src/ScriptCs.Core/IAssemblyName.cs create mode 100644 src/ScriptCs.Core/IAssemblyResolver.cs delete mode 100644 src/ScriptCs/Command/ScriptCommand.cs diff --git a/src/ScriptCs.Core/AssemblyName.cs b/src/ScriptCs.Core/AssemblyName.cs deleted file mode 100644 index ffaea2b5..00000000 --- a/src/ScriptCs.Core/AssemblyName.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ScriptCs -{ - public class AssemblyName : IAssemblyName - { - public System.Reflection.AssemblyName GetAssemblyName(string path) - { - return System.Reflection.AssemblyName.GetAssemblyName(path); - } - } -} diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs new file mode 100644 index 00000000..80f42471 --- /dev/null +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +using Common.Logging; + +namespace ScriptCs +{ + public class AssemblyResolver : IAssemblyResolver + { + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + + private readonly IFileSystem _fileSystem; + + private readonly ILog _logger; + + public AssemblyResolver(IPackageAssemblyResolver packageAssemblyResolver, IFileSystem fileSystem, ILog logger) + { + _packageAssemblyResolver = packageAssemblyResolver; + _fileSystem = fileSystem; + _logger = logger; + } + + public IEnumerable GetAssemblyPaths(string path) + { + var assemblyPaths = new List(); + + var packagesFolder = Path.Combine(path, Constants.PackagesFolder); + + if (_fileSystem.DirectoryExists(packagesFolder)) + { + var packageAssemblies = _packageAssemblyResolver.GetAssemblyNames(path); + assemblyPaths.AddRange(packageAssemblies); + } + + var looseAssemblies = _fileSystem.EnumerateFiles(path, "*.dll", SearchOption.TopDirectoryOnly) + .Union(_fileSystem.EnumerateFiles(path, "*.exe", SearchOption.TopDirectoryOnly)) + .Where(IsManagedAssembly); + + assemblyPaths.AddRange(looseAssemblies); + + foreach (var assemblyPath in assemblyPaths) + { + _logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(assemblyPath)); + } + + return assemblyPaths; + } + + private static bool IsManagedAssembly(string path) + { + try + { + AssemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return false; + } + return true; + } + } +} diff --git a/src/ScriptCs.Core/IAssemblyName.cs b/src/ScriptCs.Core/IAssemblyName.cs deleted file mode 100644 index 3d2d9dd8..00000000 --- a/src/ScriptCs.Core/IAssemblyName.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ScriptCs -{ - public interface IAssemblyName - { - System.Reflection.AssemblyName GetAssemblyName(string path); - } -} diff --git a/src/ScriptCs.Core/IAssemblyResolver.cs b/src/ScriptCs.Core/IAssemblyResolver.cs new file mode 100644 index 00000000..04bc3338 --- /dev/null +++ b/src/ScriptCs.Core/IAssemblyResolver.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public interface IAssemblyResolver + { + IEnumerable GetAssemblyPaths(string path); + } +} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 6d370643..359abae1 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -42,7 +42,7 @@ - + @@ -56,7 +56,7 @@ - + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d95970ef..f322affb 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -25,12 +25,11 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, - _scriptServiceRoot.AssemblyName); + _scriptServiceRoot.AssemblyResolver); return replCommand; } @@ -43,9 +42,8 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Logger, - _scriptServiceRoot.AssemblyName); + _scriptServiceRoot.AssemblyResolver); var fileSystem = _scriptServiceRoot.FileSystem; var currentDirectory = fileSystem.CurrentDirectory; diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 8efb94d7..95d5d3ed 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -5,35 +5,49 @@ namespace ScriptCs.Command { - internal class ExecuteReplCommand : ScriptCommand + internal class ExecuteReplCommand : IScriptCommand { private readonly IScriptPackResolver _scriptPackResolver; + + private readonly IAssemblyResolver _assemblyResolver; + private readonly IFilePreProcessor _filePreProcessor; + private readonly IScriptEngine _scriptEngine; + + private readonly IFileSystem _fileSystem; + private readonly IConsole _console; + private readonly ILog _logger; + public ExecuteReplCommand( IFileSystem fileSystem, IScriptPackResolver scriptPackResolver, - IPackageAssemblyResolver packageAssemblyResolver, IScriptEngine scriptEngine, IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssemblyName assemblyName) : base(fileSystem, packageAssemblyResolver, assemblyName, logger) + IAssemblyResolver assemblyResolver) { + _fileSystem = fileSystem; _scriptPackResolver = scriptPackResolver; _scriptEngine = scriptEngine; _filePreProcessor = filePreProcessor; + _logger = logger; _console = console; + _assemblyResolver = assemblyResolver; } - public override CommandResult Execute() + public string[] ScriptArgs { get; private set; } + + public CommandResult Execute() { _console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); - var repl = new Repl(FileSystem, _scriptEngine, Logger, _console, _filePreProcessor); + var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console, _filePreProcessor); - var assemblies = GetAssemblyPaths(FileSystem.CurrentDirectory); + var workingDirectory = _fileSystem.CurrentDirectory; + var assemblies = _assemblyResolver.GetAssemblyPaths(workingDirectory); var scriptPacks = _scriptPackResolver.GetPacks(); repl.Initialize(assemblies, scriptPacks); @@ -44,7 +58,7 @@ public override CommandResult Execute() } catch (Exception ex) { - Logger.Error(ex.Message); + _logger.Error(ex.Message); return CommandResult.Error; } diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 298e0f51..8bff52b7 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -4,37 +4,49 @@ namespace ScriptCs.Command { - internal class ExecuteScriptCommand : ScriptCommand + internal class ExecuteScriptCommand : IScriptCommand { - private readonly string _script; - private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; + private readonly IAssemblyResolver _assemblyResolver; + + private readonly IScriptExecutor _scriptExecutor; + + private readonly IFileSystem _fileSystem; + + private readonly string _script; + + private readonly ILog _logger; + public ExecuteScriptCommand(string script, string[] scriptArgs, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, - IPackageAssemblyResolver packageAssemblyResolver, ILog logger, - IAssemblyName assemblyName) : base(fileSystem, packageAssemblyResolver, assemblyName, logger) + IAssemblyResolver assemblyResolver) { _script = script; + _fileSystem = fileSystem; ScriptArgs = scriptArgs; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; + _logger = logger; + _assemblyResolver = assemblyResolver; } - public override CommandResult Execute() + public string[] ScriptArgs { get; private set; } + + public CommandResult Execute() { try { var assemblyPaths = Enumerable.Empty(); - var workingDirectory = FileSystem.GetWorkingDirectory(_script); + var workingDirectory = _fileSystem.GetWorkingDirectory(_script); if (workingDirectory != null) { - assemblyPaths = GetAssemblyPaths(workingDirectory); + assemblyPaths = _assemblyResolver.GetAssemblyPaths(workingDirectory); } _scriptExecutor.Initialize(assemblyPaths, _scriptPackResolver.GetPacks()); _scriptExecutor.Execute(_script, ScriptArgs); @@ -44,7 +56,7 @@ public override CommandResult Execute() } catch (Exception ex) { - Logger.Error(ex.Message); + _logger.Error(ex.Message); return CommandResult.Error; } } diff --git a/src/ScriptCs/Command/ScriptCommand.cs b/src/ScriptCs/Command/ScriptCommand.cs deleted file mode 100644 index 32fef83a..00000000 --- a/src/ScriptCs/Command/ScriptCommand.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using Common.Logging; - -namespace ScriptCs.Command -{ - public abstract class ScriptCommand : IScriptCommand - { - protected readonly IFileSystem FileSystem; - - protected readonly ILog Logger; - - private readonly IPackageAssemblyResolver _packageAssemblyResolver; - - private readonly IAssemblyName _assemblyName; - - protected ScriptCommand( - IFileSystem fileSystem, - IPackageAssemblyResolver packageAssemblyResolver, - IAssemblyName assemblyName, - ILog logger) - { - FileSystem = fileSystem; - _packageAssemblyResolver = packageAssemblyResolver; - _assemblyName = assemblyName; - Logger = logger; - } - - public string[] ScriptArgs { get; protected set; } - - public abstract CommandResult Execute(); - - protected IEnumerable GetAssemblyPaths(string workingDirectory) - { - var assemblyPaths = new List(); - - var packagesFolder = Path.Combine(workingDirectory, Constants.PackagesFolder); - if (FileSystem.DirectoryExists(packagesFolder)) - { - var packageAssemblies = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); - assemblyPaths.AddRange(packageAssemblies); - } - - var looseAssemblies = FileSystem.EnumerateFiles(workingDirectory, "*.dll", SearchOption.TopDirectoryOnly) - .Union(FileSystem.EnumerateFiles(workingDirectory, "*.exe", SearchOption.TopDirectoryOnly)) - .Where(IsManagedAssembly); - - assemblyPaths.AddRange(looseAssemblies); - - foreach (var path in assemblyPaths) - { - Logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(path)); - } - - return assemblyPaths; - } - - private bool IsManagedAssembly(string path) - { - try - { - _assemblyName.GetAssemblyName(path); - } - catch (BadImageFormatException) - { - return false; - } - return true; - } - } -} \ No newline at end of file diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index dbb50cad..b883d53c 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -50,7 +50,7 @@ public void Initialize() typeof (NugetInstallationProvider), typeof (PackageInstaller), typeof (ReplConsole), - typeof (AssemblyName) + typeof (AssemblyResolver) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index ad33743f..4f413311 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -63,7 +63,6 @@ - diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index ac2c90e7..d8d665bb 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -15,7 +15,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssemblyName assemblyName, + IAssemblyResolver assemblyResolver, IConsole console = null) { FileSystem = fileSystem; @@ -27,7 +27,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - AssemblyName = assemblyName; + AssemblyResolver = assemblyResolver; } public IFileSystem FileSystem { get; private set; } @@ -39,6 +39,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssemblyName AssemblyName { get; private set; } + public IAssemblyResolver AssemblyResolver { get; private set; } } } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index b4526fcd..62553def 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -23,7 +23,7 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index cc8247dd..353d9030 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -29,7 +29,7 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index da9a7dd1..d86e3ed0 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -36,7 +36,7 @@ public void ShouldPromptForInput() Mock.Of(), Mock.Of(), Mock.Of(), - Mock.Of(), + Mock.Of(), console); var commandFactory = new CommandFactory(root); diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c2fa5d2f..cd35d1d0 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -6,7 +6,6 @@ using ScriptCs.Contracts; using ScriptCs.Package; using Xunit; -using System; using System.Linq; namespace ScriptCs.Tests @@ -35,7 +34,7 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); @@ -74,8 +73,7 @@ public void NonManagedAssembliesAreExcluded() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 13c9ebbc..c1e4efaa 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,7 +37,7 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); @@ -71,7 +71,7 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index bbc7f11e..8546f5e8 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,7 +42,7 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); From 7540fc357673db75604a7e1f54d3e225f26f3d6a Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 27 May 2013 18:02:58 +0200 Subject: [PATCH 0284/1224] Added ScriptManifest, InstallCommand writes the manifest, while AssemblyResolver reads it. --- src/ScriptCs.Core/AssemblyResolver.cs | 52 ++++++++++++++++---------- src/ScriptCs.Core/Constants.cs | 2 +- src/ScriptCs.Core/FileSystem.cs | 5 +++ src/ScriptCs.Core/IFileSystem.cs | 2 + src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs.Core/ScriptManifest.cs | 14 +++++++ src/ScriptCs/Command/InstallCommand.cs | 22 +++++++++++ src/ScriptCs/ScriptCs.csproj | 4 ++ 8 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 src/ScriptCs.Core/ScriptManifest.cs diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index 80f42471..3a44186f 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -6,41 +6,31 @@ using Common.Logging; +using ServiceStack.Text; + namespace ScriptCs { public class AssemblyResolver : IAssemblyResolver { - private readonly IPackageAssemblyResolver _packageAssemblyResolver; - private readonly IFileSystem _fileSystem; private readonly ILog _logger; - public AssemblyResolver(IPackageAssemblyResolver packageAssemblyResolver, IFileSystem fileSystem, ILog logger) + public AssemblyResolver(IFileSystem fileSystem, ILog logger) { - _packageAssemblyResolver = packageAssemblyResolver; _fileSystem = fileSystem; _logger = logger; } public IEnumerable GetAssemblyPaths(string path) { - var assemblyPaths = new List(); - - var packagesFolder = Path.Combine(path, Constants.PackagesFolder); + Guard.AgainstNullArgument("path", path); - if (_fileSystem.DirectoryExists(packagesFolder)) - { - var packageAssemblies = _packageAssemblyResolver.GetAssemblyNames(path); - assemblyPaths.AddRange(packageAssemblies); - } - - var looseAssemblies = _fileSystem.EnumerateFiles(path, "*.dll", SearchOption.TopDirectoryOnly) - .Union(_fileSystem.EnumerateFiles(path, "*.exe", SearchOption.TopDirectoryOnly)) - .Where(IsManagedAssembly); - - assemblyPaths.AddRange(looseAssemblies); + var manifestAssemblies = GetManifestAssemblies(path); + var looseAssemblies = GetLooseAssemblies(path); + var assemblyPaths = manifestAssemblies.Union(looseAssemblies).ToList(); + foreach (var assemblyPath in assemblyPaths) { _logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(assemblyPath)); @@ -49,17 +39,41 @@ public IEnumerable GetAssemblyPaths(string path) return assemblyPaths; } + private IEnumerable GetLooseAssemblies(string path) + { + var binFolder = Path.Combine(path, Constants.BinFolder); + if (!_fileSystem.DirectoryExists(binFolder)) + return Enumerable.Empty(); + + var looseAssemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") + .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) + .Where(IsManagedAssembly); + + return looseAssemblies; + } + + private IEnumerable GetManifestAssemblies(string path) + { + var manifestPath = Path.Combine(path, Constants.ManifestFile); + if (!_fileSystem.FileExists(manifestPath)) + return Enumerable.Empty(); + + var manifest = _fileSystem.ReadFile(manifestPath).FromJson(); + + return manifest.PackageAssemblies; + } + private static bool IsManagedAssembly(string path) { try { AssemblyName.GetAssemblyName(path); + return true; } catch (BadImageFormatException) { return false; } - return true; } } } diff --git a/src/ScriptCs.Core/Constants.cs b/src/ScriptCs.Core/Constants.cs index 62a745b0..3780943d 100644 --- a/src/ScriptCs.Core/Constants.cs +++ b/src/ScriptCs.Core/Constants.cs @@ -7,7 +7,7 @@ public static class Constants public const string PackagesFolder = "packages"; public const string BinFolder = "bin"; public const string DefaultRepositoryUrl = "https://nuget.org/api/v2/"; - + public const string ManifestFile = "manifest.json"; public const string DebugContractName = "Debug"; public const string RunContractName = "Run"; } diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 3a9299cf..81fb13b9 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -81,6 +81,11 @@ public IEnumerable SplitLines(string value) return value.Split(new[] { NewLine }, StringSplitOptions.None); } + public void WriteToFile(string path, string text) + { + File.WriteAllText(path, text); + } + public Stream CreateFileStream(string filePath, FileMode mode) { return new FileStream(filePath, mode); diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 15a975f4..fdb62ce3 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -39,6 +39,8 @@ public interface IFileSystem void FileDelete(string path); IEnumerable SplitLines(string value); + + void WriteToFile(string path, string text); Stream CreateFileStream(string filePath, FileMode mode); } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 359abae1..d689d893 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -82,6 +82,7 @@ + diff --git a/src/ScriptCs.Core/ScriptManifest.cs b/src/ScriptCs.Core/ScriptManifest.cs new file mode 100644 index 00000000..72d482db --- /dev/null +++ b/src/ScriptCs.Core/ScriptManifest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public class ScriptManifest + { + public ScriptManifest() + { + PackageAssemblies = new HashSet(); + } + + public HashSet PackageAssemblies { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index 319d79bf..f8d315de 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.Versioning; using Common.Logging; using ScriptCs.Package; +using ServiceStack.Text; + namespace ScriptCs.Command { internal class InstallCommand : IInstallCommand @@ -47,6 +50,8 @@ public CommandResult Execute() { _packageInstaller.InstallPackages(packages, _allowPre, _logger.Info); + UpdateManifest(workingDirectory); + _logger.Info("Installation completed successfully."); return CommandResult.Success; } @@ -57,6 +62,23 @@ public CommandResult Execute() } } + private void UpdateManifest(string workingDirectory) + { + var manifestPath = Path.Combine(workingDirectory, Constants.ManifestFile); + var manifest = GetManifest(manifestPath) ?? new ScriptManifest(); + + var installedPackages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); + manifest.PackageAssemblies.UnionWith(installedPackages); + + _fileSystem.WriteToFile(manifestPath, manifest.ToJson()); + } + + private ScriptManifest GetManifest(string manifestPath) + { + if (!_fileSystem.FileExists(manifestPath)) return null; + return _fileSystem.ReadFile(manifestPath).To(); + } + private IEnumerable GetPackages(string workingDirectory) { if (string.IsNullOrWhiteSpace(_name)) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 4f413311..92d42933 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -38,6 +38,10 @@ False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll + + False + ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll + From e583fe0335005a1136641f764838af8df86b7758 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 27 May 2013 18:05:50 +0200 Subject: [PATCH 0285/1224] Fixed bug where manifest wasn't deserialized --- src/ScriptCs/Command/InstallCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index f8d315de..a7455712 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -76,7 +76,7 @@ private void UpdateManifest(string workingDirectory) private ScriptManifest GetManifest(string manifestPath) { if (!_fileSystem.FileExists(manifestPath)) return null; - return _fileSystem.ReadFile(manifestPath).To(); + return _fileSystem.ReadFile(manifestPath).FromJson(); } private IEnumerable GetPackages(string workingDirectory) From 3f72a1ff7de7317042b14e130b84e2daadcae9bc Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 27 May 2013 23:02:06 +0200 Subject: [PATCH 0286/1224] Added more logging --- src/ScriptCs.Core/AssemblyResolver.cs | 25 +++++++++++++++---------- src/ScriptCs/Command/InstallCommand.cs | 2 ++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index 3a44186f..985fee94 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -29,14 +29,7 @@ public IEnumerable GetAssemblyPaths(string path) var manifestAssemblies = GetManifestAssemblies(path); var looseAssemblies = GetLooseAssemblies(path); - var assemblyPaths = manifestAssemblies.Union(looseAssemblies).ToList(); - - foreach (var assemblyPath in assemblyPaths) - { - _logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(assemblyPath)); - } - - return assemblyPaths; + return manifestAssemblies.Union(looseAssemblies); } private IEnumerable GetLooseAssemblies(string path) @@ -47,7 +40,13 @@ private IEnumerable GetLooseAssemblies(string path) var looseAssemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) - .Where(IsManagedAssembly); + .Where(IsManagedAssembly) + .ToList(); + + foreach (var looseAssembly in looseAssemblies) + { + _logger.DebugFormat("Found assembly in bin folder: {0}", Path.GetFileName(looseAssembly)); + } return looseAssemblies; } @@ -60,10 +59,15 @@ private IEnumerable GetManifestAssemblies(string path) var manifest = _fileSystem.ReadFile(manifestPath).FromJson(); + foreach (var packageAssembly in manifest.PackageAssemblies) + { + _logger.DebugFormat("Found package assembly: {0}", Path.GetFileName(packageAssembly)); + } + return manifest.PackageAssemblies; } - private static bool IsManagedAssembly(string path) + private bool IsManagedAssembly(string path) { try { @@ -72,6 +76,7 @@ private static bool IsManagedAssembly(string path) } catch (BadImageFormatException) { + _logger.DebugFormat("Skipping non-managed assembly: {0}", Path.GetFileName(path)); return false; } } diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index a7455712..8a646df2 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -71,6 +71,8 @@ private void UpdateManifest(string workingDirectory) manifest.PackageAssemblies.UnionWith(installedPackages); _fileSystem.WriteToFile(manifestPath, manifest.ToJson()); + + _logger.InfoFormat("{0} written to {1}.", Constants.ManifestFile, workingDirectory); } private ScriptManifest GetManifest(string manifestPath) From a07ea4d2006be5338d51add0fdc83caa56d3a193 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 28 May 2013 00:17:37 +0200 Subject: [PATCH 0287/1224] Refactored out check for managed assemblies into IAssemblyUtility, added tests for IAssemblyResolver --- src/ScriptCs.Core/AssemblyResolver.cs | 25 ++---- src/ScriptCs.Core/AssemblyUtility.cs | 21 +++++ src/ScriptCs.Core/IAssemblyUtility.cs | 7 ++ src/ScriptCs.Core/ScriptCs.Core.csproj | 2 + src/ScriptCs/CompositionRoot.cs | 3 +- .../AssemblyResolverTests.cs | 87 +++++++++++++++++++ .../ScriptCs.Core.Tests.csproj | 1 + 7 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 src/ScriptCs.Core/AssemblyUtility.cs create mode 100644 src/ScriptCs.Core/IAssemblyUtility.cs create mode 100644 test/ScriptCs.Core.Tests/AssemblyResolverTests.cs diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index 985fee94..f0e321a9 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; using Common.Logging; @@ -16,10 +14,13 @@ public class AssemblyResolver : IAssemblyResolver private readonly ILog _logger; - public AssemblyResolver(IFileSystem fileSystem, ILog logger) + private readonly IAssemblyUtility _assemblyUtility; + + public AssemblyResolver(IFileSystem fileSystem, IAssemblyUtility assemblyUtility, ILog logger) { _fileSystem = fileSystem; _logger = logger; + _assemblyUtility = assemblyUtility; } public IEnumerable GetAssemblyPaths(string path) @@ -40,7 +41,7 @@ private IEnumerable GetLooseAssemblies(string path) var looseAssemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) - .Where(IsManagedAssembly) + .Where(_assemblyUtility.IsManagedAssembly) .ToList(); foreach (var looseAssembly in looseAssemblies) @@ -66,19 +67,5 @@ private IEnumerable GetManifestAssemblies(string path) return manifest.PackageAssemblies; } - - private bool IsManagedAssembly(string path) - { - try - { - AssemblyName.GetAssemblyName(path); - return true; - } - catch (BadImageFormatException) - { - _logger.DebugFormat("Skipping non-managed assembly: {0}", Path.GetFileName(path)); - return false; - } - } } } diff --git a/src/ScriptCs.Core/AssemblyUtility.cs b/src/ScriptCs.Core/AssemblyUtility.cs new file mode 100644 index 00000000..5a9346eb --- /dev/null +++ b/src/ScriptCs.Core/AssemblyUtility.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; + +namespace ScriptCs +{ + public class AssemblyUtility : IAssemblyUtility + { + public bool IsManagedAssembly(string path) + { + try + { + AssemblyName.GetAssemblyName(path); + return true; + } + catch (BadImageFormatException) + { + return false; + } + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/IAssemblyUtility.cs b/src/ScriptCs.Core/IAssemblyUtility.cs new file mode 100644 index 00000000..805b4d5b --- /dev/null +++ b/src/ScriptCs.Core/IAssemblyUtility.cs @@ -0,0 +1,7 @@ +namespace ScriptCs +{ + public interface IAssemblyUtility + { + bool IsManagedAssembly(string assemblyPath); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index d689d893..49a9e148 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -43,6 +43,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index b883d53c..59b4b872 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -50,7 +50,8 @@ public void Initialize() typeof (NugetInstallationProvider), typeof (PackageInstaller), typeof (ReplConsole), - typeof (AssemblyResolver) + typeof (AssemblyResolver), + typeof (AssemblyUtility) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs new file mode 100644 index 00000000..1e64bb9a --- /dev/null +++ b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs @@ -0,0 +1,87 @@ +using System.IO; +using System.Linq; + +using Common.Logging; + +using Moq; + +using Should; + +using Xunit; + +namespace ScriptCs.Tests +{ + public class AssemblyResolverTests + { + public class GetAssemblyPathsMethod + { + [Fact] + public void ShouldReturnAssembliesFromManifestFile() + { + const string WorkingDirectory = @"C:\"; + + var assemblyFile = Path.Combine(WorkingDirectory, @"C:\MyAssembly.dll"); + var manifestFile = Path.Combine(WorkingDirectory, Constants.ManifestFile); + + var fileSystem = new Mock(); + fileSystem.Setup(x => x.FileExists(manifestFile)).Returns(true); + fileSystem.Setup(x => x.ReadFile(manifestFile)).Returns(@"{ ""PackageAssemblies"": [ " + assemblyFile + " ] }"); + + var resolver = new AssemblyResolver(fileSystem.Object, Mock.Of(), Mock.Of()); + + var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); + + assemblies.Count.ShouldEqual(1); + assemblies[0].ShouldEqual(assemblyFile); + } + + [Fact] + public void ShouldReturnAssembliesFromBinFolder() + { + const string WorkingDirectory = @"C:\"; + + var binFolder = Path.Combine(WorkingDirectory, "bin"); + var assemblyFile = Path.Combine(binFolder, "MyAssembly.dll"); + + var fileSystem = new Mock(); + fileSystem.Setup(x => x.DirectoryExists(binFolder)).Returns(true); + fileSystem.Setup(x => x.EnumerateFiles(binFolder, It.IsAny(), SearchOption.AllDirectories)).Returns(new[] { assemblyFile }); + + var assemblyUtility = new Mock(); + assemblyUtility.Setup(x => x.IsManagedAssembly(assemblyFile)).Returns(true); + + var resolver = new AssemblyResolver(fileSystem.Object, assemblyUtility.Object, Mock.Of()); + + var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); + + assemblies.Count.ShouldEqual(1); + assemblies[0].ShouldEqual(assemblyFile); + } + + [Fact] + public void ShouldNotReturnNonManagedAssemblies() + { + const string WorkingDirectory = @"C:\"; + + var binFolder = Path.Combine(WorkingDirectory, "bin"); + var managed = Path.Combine(binFolder, "MyAssembly.dll"); + var nonManaged = Path.Combine(binFolder, "MyAssembly.dll"); + + var fileSystem = new Mock(); + fileSystem.Setup(x => x.DirectoryExists(binFolder)).Returns(true); + fileSystem.Setup(x => x.EnumerateFiles(binFolder, It.IsAny(), SearchOption.AllDirectories)) + .Returns(new[] { managed, nonManaged }); + + var assemblyUtility = new Mock(); + assemblyUtility.Setup(x => x.IsManagedAssembly(managed)).Returns(true); + + var resolver = new AssemblyResolver(fileSystem.Object, assemblyUtility.Object, Mock.Of()); + + var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); + + assemblies.Count.ShouldEqual(1); + assemblies[0].ShouldEqual(managed); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index e61da225..6e1c08e4 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -37,6 +37,7 @@ Properties\CommonVersionInfo.cs + From 172ee9bc276b0dce2ea6a3e6a0bce57f1545b089 Mon Sep 17 00:00:00 2001 From: Michael Wade Date: Tue, 28 May 2013 10:26:09 +0100 Subject: [PATCH 0288/1224] Using correct assertion library and returning the correct path if the path is a filename or directory. Would prefer if it was all in memory, but unsure as to how it should be designed. --- src/ScriptCs.Core/FileSystem.cs | 7 ++++++- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index bc503b7f..0d6bb702 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -90,7 +90,12 @@ public string GetWorkingDirectory(string path) { var realPath = GetFullPath(path); - return Path.GetFileName(realPath) == string.Empty ? realPath : Path.GetDirectoryName(realPath); + var attributes = File.GetAttributes(realPath); + + if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) + return realPath; + else + return Path.GetDirectoryName(realPath); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 1b26fbf3..bbd36d24 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -158,9 +158,20 @@ public void DoNotChangePathIfAbsolute() [Fact] public void ShouldResolveAssemblyReferencesCorrectlyWhenNotRunFromCSXFolder() { - var fileSystem = new FileSystem(); + const string pathToMyScriptFolder = @"..\my_script\"; - Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory,@"..\my_script\")), fileSystem.GetWorkingDirectory(@"..\my_script\")); + try { + Directory.CreateDirectory(pathToMyScriptFolder); + + var fileSystem = new FileSystem(); + + fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); + } + finally { + if (Directory.Exists(pathToMyScriptFolder)) + Directory.Delete(pathToMyScriptFolder); + } } [Fact] From ffcc6bf445129589710ce1303ec0c0a315283d24 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 28 May 2013 15:53:37 -0400 Subject: [PATCH 0289/1224] Update ServiceStack.Text from 3.9.44 to 3.9.47 --- src/ScriptCs/packages.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index 2928ed03..9531ddb6 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -6,5 +6,5 @@ - - + + \ No newline at end of file From b87af11fbbaced38b3fcb82466d2a9b9a35c028a Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 28 May 2013 15:57:23 -0400 Subject: [PATCH 0290/1224] ScriptCs and ScriptCs.Core should reference ServiceStack.Text v3.9.47 instead of v3.9.44 --- src/ScriptCs.Core/ScriptCs.Core.csproj | 2 +- src/ScriptCs.Core/packages.config | 3 +-- src/ScriptCs/ScriptCs.csproj | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 6d370643..63f91f59 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -30,7 +30,7 @@ ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll - ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll + ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 953a2ce5..0d6dfbdf 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -3,7 +3,6 @@ - - + \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index d0a48452..5fc6d0e2 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -38,6 +38,10 @@ False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll + + False + ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll + From 21458b910cbb4e6c5ebf291a79fe0d902914de73 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 30 May 2013 10:10:03 +0200 Subject: [PATCH 0291/1224] Fixed bad merge --- src/ScriptCs/ScriptCs.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 3e946e49..5a735557 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -38,9 +38,6 @@ False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll - - False - ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll False ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll From 5e8eb07dcae2cb104346328f8ce5eeb183f667f7 Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 31 May 2013 14:40:51 +0200 Subject: [PATCH 0292/1224] fixes #306 - if there is compile/execution exception it gets shown in the console (script mode) or REPL (repl mode) --- src/ScriptCs.Core/IScriptExecutor.cs | 4 +- src/ScriptCs.Core/Repl.cs | 21 +++++- src/ScriptCs.Core/ScriptExecutor.cs | 8 +-- src/ScriptCs/Command/ExecuteScriptCommand.cs | 21 +++++- .../ExecuteScriptCommandTests.cs | 70 +++++++++++++++++++ 5 files changed, 113 insertions(+), 11 deletions(-) diff --git a/src/ScriptCs.Core/IScriptExecutor.cs b/src/ScriptCs.Core/IScriptExecutor.cs index 8cca24d9..06e404e7 100644 --- a/src/ScriptCs.Core/IScriptExecutor.cs +++ b/src/ScriptCs.Core/IScriptExecutor.cs @@ -6,8 +6,8 @@ namespace ScriptCs public interface IScriptExecutor { void Initialize(IEnumerable paths, IEnumerable scriptPacks); - void Execute(string script, string[] scriptArgs); - void Execute(string script); + ScriptResult Execute(string script, string[] scriptArgs); + ScriptResult Execute(string script); void Terminate(); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 04e16a75..15ab16e8 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -24,7 +24,7 @@ public override void Terminate() Console.Exit(); } - public override void Execute(string script) + public override ScriptResult Execute(string script) { try { @@ -53,21 +53,36 @@ public override void Execute(string script) throw new FileNotFoundException(string.Format("Could not find assembly '{0}'", assemblyPath), assemblyPath); } - return; + return new ScriptResult(); } Console.ForegroundColor = ConsoleColor.Cyan; var result = ScriptEngine.Execute(script, new string[0], References, DefaultNamespaces, ScriptPackSession); if (result != null) { + if (result.CompileException != null) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.Write(result.CompileException.ToString()); + } + + if (result.ExecuteException != null) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.Write(result.ExecuteException.ToString()); + } + Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ToJsv()); + Console.WriteLine(result.ReturnValue.ToJsv()); } + + return result; } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + ex + "\r\n"); + return new ScriptResult(); } finally { diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 5d77e354..46e02aa1 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -46,19 +46,19 @@ public virtual void Terminate() ScriptPackSession.TerminatePacks(); } - public virtual void Execute(string script) + public virtual ScriptResult Execute(string script) { - Execute(script, new string[0]); + return Execute(script, new string[0]); } - public virtual void Execute(string script, string[] scriptArgs) + public virtual ScriptResult Execute(string script, string[] scriptArgs) { var path = Path.IsPathRooted(script) ? script : Path.Combine(FileSystem.CurrentDirectory, script); var result = FilePreProcessor.ProcessFile(path); var references = References.Union(result.References); Logger.Debug("Starting execution in engine"); - ScriptEngine.Execute(result.Code, scriptArgs, references, DefaultNamespaces, ScriptPackSession); + return ScriptEngine.Execute(result.Code, scriptArgs, references, DefaultNamespaces, ScriptPackSession); } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 163b353d..80cabf30 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -48,10 +48,27 @@ public CommandResult Execute() assemblyPaths = GetAssemblyPaths(workingDirectory); } _scriptExecutor.Initialize(assemblyPaths, _scriptPackResolver.GetPacks()); - _scriptExecutor.Execute(_script, ScriptArgs); + var result = _scriptExecutor.Execute(_script, ScriptArgs); _scriptExecutor.Terminate(); - return CommandResult.Success; + if (result != null) + { + if (result.CompileException != null) + { + _logger.Error(result.CompileException); + return CommandResult.Error; + } + + if (result.ExecuteException != null) + { + _logger.Error(result.ExecuteException); + return CommandResult.Error; + } + + return CommandResult.Success; + } + + return CommandResult.Error; } catch (Exception ex) { diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index a0c49a9c..f2627768 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -121,6 +121,76 @@ public void NonManagedAssembliesAreExcluded() executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); executor.Verify(i => i.Terminate(), Times.Once()); } + + [Fact] + public void ShouldReturnErrorIfThereIsCompileException() + { + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + + var resolver = new Mock(); + var executor = new Mock(); + executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) + .Returns(new ScriptResult {CompileException = new Exception("test")}); + + var engine = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var logger = new Mock(); + var filePreProcessor = new Mock(); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + var commandResult = result.Execute(); + + Assert.Equal(CommandResult.Error, commandResult); + logger.Verify(i => i.Error(It.IsAny()),Times.Once()); + } + + [Fact] + public void ShouldReturnErrorIfThereIsExecuteException() + { + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + + var resolver = new Mock(); + var executor = new Mock(); + executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) + .Returns(new ScriptResult { ExecuteException = new Exception("test") }); + + var engine = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var logger = new Mock(); + var filePreProcessor = new Mock(); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + var commandResult = result.Execute(); + + Assert.Equal(CommandResult.Error, commandResult); + logger.Verify(i => i.Error(It.IsAny()), Times.Once()); + } } } } From 9d92f94cf739ca6223923007d4ce37c325b5e66f Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 31 May 2013 14:45:38 +0200 Subject: [PATCH 0293/1224] pass exception to REPL from the catch block too --- src/ScriptCs.Core/Repl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 15ab16e8..ef71d0a3 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -82,7 +82,7 @@ public override ScriptResult Execute(string script) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + ex + "\r\n"); - return new ScriptResult(); + return new ScriptResult { ExecuteException = ex }; } finally { From e666f7b78a87139cf314b3dcb3c2f19c0a788d48 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 2 Jun 2013 11:35:47 +0200 Subject: [PATCH 0294/1224] add assembly reference to REPL reference list regardless whether it exists or not. Then catch on exception and remove reference if needed --- src/ScriptCs.Core/Repl.cs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 04e16a75..a2eb5f68 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -38,20 +38,14 @@ public override void Execute(string script) } else { - throw new FileNotFoundException(string.Format("Could not find script '{0}'", filepath), filepath); + throw new FileLoadException(string.Format("Could not find script '{0}'", filepath), filepath); } } else if (PreProcessorUtil.IsRLine(script)) { - var assemblyPath = FileSystem.GetFullPath(Path.Combine(Constants.BinFolder, PreProcessorUtil.GetPath(PreProcessorUtil.RString, script))); - if (FileSystem.FileExists(assemblyPath)) - { - References = References.Union(new[] { assemblyPath }); - } - else - { - throw new FileNotFoundException(string.Format("Could not find assembly '{0}'", assemblyPath), assemblyPath); - } + var assemblyName = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); + var assemblyPath = FileSystem.GetFullPath(Path.Combine(Constants.BinFolder, assemblyName)); + References = References.Union(FileSystem.FileExists(assemblyPath) ? new[] { assemblyPath } : new[] { assemblyName }); return; } @@ -61,9 +55,18 @@ public override void Execute(string script) if (result != null) { Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ToJsv()); + Console.WriteLine(result.ReturnValue.ToJsv()); } } + catch (FileNotFoundException fileEx) + { + if (References.Any(i => i == fileEx.FileName)) + { + References = References.Except(new[] {fileEx.FileName}); + } + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("\r\n" + fileEx + "\r\n"); + } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; From 9da7e3a5225d1a230dd38923e303648ee03ab474 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 2 Jun 2013 11:36:56 +0200 Subject: [PATCH 0295/1224] added tests for verifying that assembly gets removed from REPL reference list if it wasnt found. Also check - if file exists reference by absolute path, otherwise try get it from GAC --- test/ScriptCs.Tests/ReplTests.cs | 35 +++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index d8b4c627..63b42a37 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -228,33 +229,53 @@ public void ShouldReferenceAssemblyIfLineIsAReference() } [Fact] - public void ShouldNotReferenceAssemblyIfFileDoesNotExist() + public void ShouldReferenceAssemblyBasedOnFullPathIfFileExists() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); - mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"c:/my.dll"); - mocks.FileSystem.Setup(x => x.FileExists("c:/my.dll")).Returns(false); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"C:/my.dll"); _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); _repl.Execute("#r \"my.dll\""); - //default references = 6 - _repl.References.Count().ShouldEqual(6); + mocks.FileSystem.Verify(x => x.FileExists("C:/my.dll"), Times.Once()); } [Fact] - public void ShouldReferenceAssemblyBasedOnFullPath() + public void ShouldReferenceAssemblyBasedOnNameIfFileDoesNotExistBecauseItLooksInGACThen() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"C:/my.dll"); + mocks.FileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(false); _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); _repl.Execute("#r \"my.dll\""); - mocks.FileSystem.Verify(x => x.FileExists("C:/my.dll"), Times.Once()); + _repl.References.Contains("my.dll").ShouldBeTrue(); + } + + [Fact] + public void ShouldRemoveReferenceIfAssemblyIsNotFound() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"C:/my.dll"); + mocks.FileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(false); + mocks.ScriptEngine.Setup( + i => + i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Throws(new FileNotFoundException("error", "my.dll")); + + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"my.dll\""); + _repl.References.Contains("my.dll").ShouldBeTrue(); + _repl.Execute("var x=1;"); + _repl.References.Contains("my.dll").ShouldBeFalse(); } [Fact] From 75739bbbe98e347cf06dd9ee872eb7307447331a Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 2 Jun 2013 11:44:02 +0200 Subject: [PATCH 0296/1224] change fileloadexception to filenotfoundexception --- src/ScriptCs.Core/Repl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index a2eb5f68..f0ac2f87 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -38,7 +38,7 @@ public override void Execute(string script) } else { - throw new FileLoadException(string.Format("Could not find script '{0}'", filepath), filepath); + throw new FileNotFoundException(string.Format("Could not find script '{0}'", filepath), filepath); } } else if (PreProcessorUtil.IsRLine(script)) From 3b727701dfc7e78694b1d6d77cc2789cb16253bb Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 2 Jun 2013 11:48:07 +0200 Subject: [PATCH 0297/1224] fixed edge case of null reference --- src/ScriptCs.Core/Repl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index f0ac2f87..452a3285 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -60,7 +60,7 @@ public override void Execute(string script) } catch (FileNotFoundException fileEx) { - if (References.Any(i => i == fileEx.FileName)) + if (References != null && References.Any(i => i == fileEx.FileName)) { References = References.Except(new[] {fileEx.FileName}); } From b1925ad2faa6c8c889a14be3b97b5c4c9b58a007 Mon Sep 17 00:00:00 2001 From: SpikeTheMaster Date: Mon, 3 Jun 2013 23:07:15 +0100 Subject: [PATCH 0298/1224] Revised filesystem test name and refactored into new class fixes test in #296 --- test/ScriptCs.Core.Tests/FileSystemTests.cs | 29 +++++++++++++++++++ .../ScriptCs.Core.Tests.csproj | 1 + .../ScriptExecutorTests.cs | 21 ++------------ 3 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 test/ScriptCs.Core.Tests/FileSystemTests.cs diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs new file mode 100644 index 00000000..a080ba72 --- /dev/null +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class FileSystemTests + { + [Fact] + public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() + { + const string pathToMyScriptFolder = @"..\my_script\"; + + try { + Directory.CreateDirectory(pathToMyScriptFolder); + + var fileSystem = new FileSystem(); + + fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); + } + finally { + if (Directory.Exists(pathToMyScriptFolder)) + Directory.Delete(pathToMyScriptFolder); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index e61da225..db99f3a1 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -37,6 +37,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index bbd36d24..14b14597 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -121,6 +121,8 @@ public void ShouldTerminateScriptPacksWhenTerminateIsCalled() public class TheExecuteMethod { + private readonly FileSystemTests FileSystemTests = new FileSystemTests(); + [Fact] public void ConstructsAbsolutePathBeforePreProcessingFile() { @@ -155,25 +157,6 @@ public void DoNotChangePathIfAbsolute() preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } - [Fact] - public void ShouldResolveAssemblyReferencesCorrectlyWhenNotRunFromCSXFolder() - { - const string pathToMyScriptFolder = @"..\my_script\"; - - try { - Directory.CreateDirectory(pathToMyScriptFolder); - - var fileSystem = new FileSystem(); - - fileSystem.GetWorkingDirectory(pathToMyScriptFolder) - .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); - } - finally { - if (Directory.Exists(pathToMyScriptFolder)) - Directory.Delete(pathToMyScriptFolder); - } - } - [Fact] public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked() { From 3b5ff1e42d0f9af419dedb1854fe0817af3c5aea Mon Sep 17 00:00:00 2001 From: SpikeTheMaster Date: Mon, 3 Jun 2013 23:18:00 +0100 Subject: [PATCH 0299/1224] Followed XUnit convention Of putting tests in a class with the name of the method they test. --- test/ScriptCs.Core.Tests/FileSystemTests.cs | 29 +++++++++++-------- .../ScriptExecutorTests.cs | 2 -- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs index a080ba72..f4004b37 100644 --- a/test/ScriptCs.Core.Tests/FileSystemTests.cs +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -7,22 +7,27 @@ namespace ScriptCs.Tests { public class FileSystemTests { - [Fact] - public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() + public class GetWorkingDirectoryMethod { - const string pathToMyScriptFolder = @"..\my_script\"; + [Fact] + public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() + { + const string pathToMyScriptFolder = @"..\my_script\"; - try { - Directory.CreateDirectory(pathToMyScriptFolder); + try + { + Directory.CreateDirectory(pathToMyScriptFolder); - var fileSystem = new FileSystem(); + var fileSystem = new FileSystem(); - fileSystem.GetWorkingDirectory(pathToMyScriptFolder) - .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); - } - finally { - if (Directory.Exists(pathToMyScriptFolder)) - Directory.Delete(pathToMyScriptFolder); + fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); + } + finally + { + if (Directory.Exists(pathToMyScriptFolder)) + Directory.Delete(pathToMyScriptFolder); + } } } } diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 14b14597..a9eecca7 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -121,8 +121,6 @@ public void ShouldTerminateScriptPacksWhenTerminateIsCalled() public class TheExecuteMethod { - private readonly FileSystemTests FileSystemTests = new FileSystemTests(); - [Fact] public void ConstructsAbsolutePathBeforePreProcessingFile() { From 28cc0dbe0a521cefa12cc89b37fa5a71d5d4ecf4 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 6 Jun 2013 08:48:19 +0200 Subject: [PATCH 0300/1224] added test for #r in GAC, moved ReplTests.cs to ScriptCs.Core.Tests.csproj to reflect proper structure --- .../ReplTests.cs | 14 ++++++++++++++ .../ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj | 1 + test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 - 3 files changed, 15 insertions(+), 1 deletion(-) rename test/{ScriptCs.Tests => ScriptCs.Core.Tests}/ReplTests.cs (94%) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Core.Tests/ReplTests.cs similarity index 94% rename from test/ScriptCs.Tests/ReplTests.cs rename to test/ScriptCs.Core.Tests/ReplTests.cs index 63b42a37..ac977553 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Core.Tests/ReplTests.cs @@ -244,6 +244,20 @@ public void ShouldReferenceAssemblyBasedOnFullPathIfFileExists() [Fact] public void ShouldReferenceAssemblyBasedOnNameIfFileDoesNotExistBecauseItLooksInGACThen() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(false); + + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"PresentationCore\""); + + _repl.References.Contains("PresentationCore").ShouldBeTrue(); + } + + [Fact] + public void ShouldReferenceAssemblyBasedOnNameWithExtensionIfFileDoesNotExistBecauseItLooksInGACThen() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index e61da225..4b6e98a0 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -41,6 +41,7 @@ + diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 97db7eeb..e64fa785 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -43,7 +43,6 @@ - From 29f7525598389a3e918f721888b3cd28b8552c5f Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 6 Jun 2013 09:13:25 +0200 Subject: [PATCH 0301/1224] fix breaking build after latest merge --- src/ScriptCs.Core/Repl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index aa5e3887..7beeb1a5 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -80,6 +80,7 @@ public override ScriptResult Execute(string script) } Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + fileEx + "\r\n"); + return new ScriptResult { CompileException = fileEx }; } catch (Exception ex) { From 5416721a4266a7ab14925fed6d0b3180d174c53b Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 6 Jun 2013 21:55:18 +0200 Subject: [PATCH 0302/1224] Fixed bug where all assemblies inside working dir was picked up by MEF --- src/ScriptCs/CompositionRoot.cs | 38 ++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 59b4b872..96e89524 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -42,9 +42,6 @@ public void Initialize() var types = new[] { typeof (ScriptHostFactory), - typeof (FileSystem), - typeof (PackageAssemblyResolver), - typeof (PackageContainer), typeof (FilePreProcessor), typeof (ScriptPackResolver), typeof (NugetInstallationProvider), @@ -69,18 +66,39 @@ public void Initialize() builder.RegisterType().As(); + // Newing up these manually to get package assemblies + var fileSystem = new FileSystem(); + var packageContainer = new PackageContainer(fileSystem); + var packageAssemblyResolver = new PackageAssemblyResolver(fileSystem, packageContainer); + + builder.RegisterInstance(fileSystem).As(); + builder.RegisterInstance(packageContainer).As(); + builder.RegisterInstance(packageAssemblyResolver).As(); + if (_shouldInitDrirectoryCatalog) { - var directory = Environment.CurrentDirectory; + var currentDirectory = Environment.CurrentDirectory; + + var assemblies = packageAssemblyResolver.GetAssemblyNames(currentDirectory).ToList(); + + var binFolder = Path.Combine(currentDirectory, Constants.BinFolder); + if (Directory.Exists(binFolder)) + { + var binAssemblies = Directory.EnumerateFiles(binFolder, "*.dll") + .Union(Directory.EnumerateFiles(binFolder, "*.exe")); + + assemblies.AddRange(binAssemblies); + } - var assemblies = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories) - .Union(Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)); + var aggregateCatalog = new AggregateCatalog(); - var directoryCatalogs = assemblies - .Select(Path.GetDirectoryName).Distinct() - .Select(x => new DirectoryCatalog(x)); + var assemblyCatalogs = assemblies.Select(x => new AssemblyCatalog(x)); + foreach (var assemblyCatalog in assemblyCatalogs) + { + aggregateCatalog.Catalogs.Add(assemblyCatalog); + } - builder.RegisterComposablePartCatalog(new AggregateCatalog(directoryCatalogs)); + builder.RegisterComposablePartCatalog(aggregateCatalog); } _container = builder.Build(); From c8e57124678a52a0528a3795d15793fc654074b4 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:11:08 +0200 Subject: [PATCH 0303/1224] Removed manifest stuff after perf. testing NuGet API alternative --- src/ScriptCs.Core/AssemblyResolver.cs | 31 ++++++++++--------- src/ScriptCs.Core/Constants.cs | 1 - src/ScriptCs.Core/ScriptCs.Core.csproj | 1 - src/ScriptCs.Core/ScriptManifest.cs | 14 --------- src/ScriptCs/Command/InstallCommand.cs | 24 -------------- src/ScriptCs/CompositionRoot.cs | 30 ++++++------------ .../AssemblyResolverTests.cs | 21 +++++++------ 7 files changed, 38 insertions(+), 84 deletions(-) delete mode 100644 src/ScriptCs.Core/ScriptManifest.cs diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index f0e321a9..7341b83b 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -4,21 +4,22 @@ using Common.Logging; -using ServiceStack.Text; - namespace ScriptCs { public class AssemblyResolver : IAssemblyResolver { private readonly IFileSystem _fileSystem; + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + private readonly ILog _logger; private readonly IAssemblyUtility _assemblyUtility; - public AssemblyResolver(IFileSystem fileSystem, IAssemblyUtility assemblyUtility, ILog logger) + public AssemblyResolver(IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IAssemblyUtility assemblyUtility, ILog logger) { _fileSystem = fileSystem; + _packageAssemblyResolver = packageAssemblyResolver; _logger = logger; _assemblyUtility = assemblyUtility; } @@ -27,10 +28,10 @@ public IEnumerable GetAssemblyPaths(string path) { Guard.AgainstNullArgument("path", path); - var manifestAssemblies = GetManifestAssemblies(path); + var packageAssemblies = GetPackageAssemblies(path); var looseAssemblies = GetLooseAssemblies(path); - return manifestAssemblies.Union(looseAssemblies); + return packageAssemblies.Union(looseAssemblies); } private IEnumerable GetLooseAssemblies(string path) @@ -39,33 +40,33 @@ private IEnumerable GetLooseAssemblies(string path) if (!_fileSystem.DirectoryExists(binFolder)) return Enumerable.Empty(); - var looseAssemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") + var assemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) .Where(_assemblyUtility.IsManagedAssembly) .ToList(); - foreach (var looseAssembly in looseAssemblies) + foreach (var assembly in assemblies) { - _logger.DebugFormat("Found assembly in bin folder: {0}", Path.GetFileName(looseAssembly)); + _logger.DebugFormat("Found assembly in bin folder: {0}", Path.GetFileName(assembly)); } - return looseAssemblies; + return assemblies; } - private IEnumerable GetManifestAssemblies(string path) + private IEnumerable GetPackageAssemblies(string path) { - var manifestPath = Path.Combine(path, Constants.ManifestFile); - if (!_fileSystem.FileExists(manifestPath)) + var packagesFolder = Path.Combine(path, Constants.PackagesFolder); + if (!_fileSystem.DirectoryExists(packagesFolder)) return Enumerable.Empty(); - var manifest = _fileSystem.ReadFile(manifestPath).FromJson(); + var assemblies = _packageAssemblyResolver.GetAssemblyNames(path).ToList(); - foreach (var packageAssembly in manifest.PackageAssemblies) + foreach (var packageAssembly in assemblies) { _logger.DebugFormat("Found package assembly: {0}", Path.GetFileName(packageAssembly)); } - return manifest.PackageAssemblies; + return assemblies; } } } diff --git a/src/ScriptCs.Core/Constants.cs b/src/ScriptCs.Core/Constants.cs index 3780943d..acfff78a 100644 --- a/src/ScriptCs.Core/Constants.cs +++ b/src/ScriptCs.Core/Constants.cs @@ -7,7 +7,6 @@ public static class Constants public const string PackagesFolder = "packages"; public const string BinFolder = "bin"; public const string DefaultRepositoryUrl = "https://nuget.org/api/v2/"; - public const string ManifestFile = "manifest.json"; public const string DebugContractName = "Debug"; public const string RunContractName = "Run"; } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index d911bae9..9c78920e 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -84,7 +84,6 @@ - diff --git a/src/ScriptCs.Core/ScriptManifest.cs b/src/ScriptCs.Core/ScriptManifest.cs deleted file mode 100644 index 72d482db..00000000 --- a/src/ScriptCs.Core/ScriptManifest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs -{ - public class ScriptManifest - { - public ScriptManifest() - { - PackageAssemblies = new HashSet(); - } - - public HashSet PackageAssemblies { get; set; } - } -} \ No newline at end of file diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index 8a646df2..319d79bf 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; -using System.IO; using System.Runtime.Versioning; using Common.Logging; using ScriptCs.Package; -using ServiceStack.Text; - namespace ScriptCs.Command { internal class InstallCommand : IInstallCommand @@ -50,8 +47,6 @@ public CommandResult Execute() { _packageInstaller.InstallPackages(packages, _allowPre, _logger.Info); - UpdateManifest(workingDirectory); - _logger.Info("Installation completed successfully."); return CommandResult.Success; } @@ -62,25 +57,6 @@ public CommandResult Execute() } } - private void UpdateManifest(string workingDirectory) - { - var manifestPath = Path.Combine(workingDirectory, Constants.ManifestFile); - var manifest = GetManifest(manifestPath) ?? new ScriptManifest(); - - var installedPackages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); - manifest.PackageAssemblies.UnionWith(installedPackages); - - _fileSystem.WriteToFile(manifestPath, manifest.ToJson()); - - _logger.InfoFormat("{0} written to {1}.", Constants.ManifestFile, workingDirectory); - } - - private ScriptManifest GetManifest(string manifestPath) - { - if (!_fileSystem.FileExists(manifestPath)) return null; - return _fileSystem.ReadFile(manifestPath).FromJson(); - } - private IEnumerable GetPackages(string workingDirectory) { if (string.IsNullOrWhiteSpace(_name)) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 96e89524..dc2f45cb 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel.Composition.Hosting; using System.IO; using System.Linq; @@ -37,7 +38,7 @@ public void Initialize() loggerConfigurator.Configure(); var logger = loggerConfigurator.GetLogger(); - builder.RegisterInstance(logger); + builder.RegisterInstance(logger).As(); var types = new[] { @@ -47,8 +48,6 @@ public void Initialize() typeof (NugetInstallationProvider), typeof (PackageInstaller), typeof (ReplConsole), - typeof (AssemblyResolver), - typeof (AssemblyUtility) }; builder.RegisterTypes(types).AsImplementedInterfaces(); @@ -66,37 +65,28 @@ public void Initialize() builder.RegisterType().As(); - // Newing up these manually to get package assemblies + // Hack to resolve assemblies for MEF catalog before building Autofac container var fileSystem = new FileSystem(); + var assemblyUtility = new AssemblyUtility(); var packageContainer = new PackageContainer(fileSystem); var packageAssemblyResolver = new PackageAssemblyResolver(fileSystem, packageContainer); + var assemblyResolver = new AssemblyResolver(fileSystem, packageAssemblyResolver, assemblyUtility, logger); builder.RegisterInstance(fileSystem).As(); + builder.RegisterInstance(assemblyUtility).As(); builder.RegisterInstance(packageContainer).As(); builder.RegisterInstance(packageAssemblyResolver).As(); + builder.RegisterInstance(assemblyResolver).As(); if (_shouldInitDrirectoryCatalog) { var currentDirectory = Environment.CurrentDirectory; - - var assemblies = packageAssemblyResolver.GetAssemblyNames(currentDirectory).ToList(); - - var binFolder = Path.Combine(currentDirectory, Constants.BinFolder); - if (Directory.Exists(binFolder)) - { - var binAssemblies = Directory.EnumerateFiles(binFolder, "*.dll") - .Union(Directory.EnumerateFiles(binFolder, "*.exe")); - - assemblies.AddRange(binAssemblies); - } + var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); var aggregateCatalog = new AggregateCatalog(); - var assemblyCatalogs = assemblies.Select(x => new AssemblyCatalog(x)); - foreach (var assemblyCatalog in assemblyCatalogs) - { - aggregateCatalog.Catalogs.Add(assemblyCatalog); - } + assemblies.Select(x => new AssemblyCatalog(x)).ToList() + .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); builder.RegisterComposablePartCatalog(aggregateCatalog); } diff --git a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs index 1e64bb9a..e50f7181 100644 --- a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs +++ b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using Common.Logging; @@ -16,18 +17,20 @@ public class AssemblyResolverTests public class GetAssemblyPathsMethod { [Fact] - public void ShouldReturnAssembliesFromManifestFile() + public void ShouldReturnAssembliesFromPackagesFolder() { const string WorkingDirectory = @"C:\"; - var assemblyFile = Path.Combine(WorkingDirectory, @"C:\MyAssembly.dll"); - var manifestFile = Path.Combine(WorkingDirectory, Constants.ManifestFile); + var packagesFolder = Path.Combine(WorkingDirectory, Constants.PackagesFolder); + var assemblyFile = Path.Combine(packagesFolder, "MyAssembly.dll"); var fileSystem = new Mock(); - fileSystem.Setup(x => x.FileExists(manifestFile)).Returns(true); - fileSystem.Setup(x => x.ReadFile(manifestFile)).Returns(@"{ ""PackageAssemblies"": [ " + assemblyFile + " ] }"); + fileSystem.Setup(x => x.FileExists(packagesFolder)).Returns(true); - var resolver = new AssemblyResolver(fileSystem.Object, Mock.Of(), Mock.Of()); + var packageAssemblyResolver = new Mock(); + packageAssemblyResolver.Setup(x => x.GetAssemblyNames(WorkingDirectory, It.IsAny>())).Returns(new[] { assemblyFile }); + + var resolver = new AssemblyResolver(fileSystem.Object, packageAssemblyResolver.Object, Mock.Of(), Mock.Of()); var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); @@ -50,7 +53,7 @@ public void ShouldReturnAssembliesFromBinFolder() var assemblyUtility = new Mock(); assemblyUtility.Setup(x => x.IsManagedAssembly(assemblyFile)).Returns(true); - var resolver = new AssemblyResolver(fileSystem.Object, assemblyUtility.Object, Mock.Of()); + var resolver = new AssemblyResolver(fileSystem.Object, Mock.Of(), assemblyUtility.Object, Mock.Of()); var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); @@ -75,7 +78,7 @@ public void ShouldNotReturnNonManagedAssemblies() var assemblyUtility = new Mock(); assemblyUtility.Setup(x => x.IsManagedAssembly(managed)).Returns(true); - var resolver = new AssemblyResolver(fileSystem.Object, assemblyUtility.Object, Mock.Of()); + var resolver = new AssemblyResolver(fileSystem.Object, Mock.Of(), assemblyUtility.Object, Mock.Of()); var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); From f007f4286b31cea035c8ed9c27f1fc913bfb128d Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:12:41 +0200 Subject: [PATCH 0304/1224] Fixed failing test --- test/ScriptCs.Core.Tests/AssemblyResolverTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs index e50f7181..aa2aa503 100644 --- a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs +++ b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs @@ -25,7 +25,7 @@ public void ShouldReturnAssembliesFromPackagesFolder() var assemblyFile = Path.Combine(packagesFolder, "MyAssembly.dll"); var fileSystem = new Mock(); - fileSystem.Setup(x => x.FileExists(packagesFolder)).Returns(true); + fileSystem.Setup(x => x.DirectoryExists(packagesFolder)).Returns(true); var packageAssemblyResolver = new Mock(); packageAssemblyResolver.Setup(x => x.GetAssemblyNames(WorkingDirectory, It.IsAny>())).Returns(new[] { assemblyFile }); From 9b850d4946b168473f33d131864d6e4626a30e9e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:19:00 +0200 Subject: [PATCH 0305/1224] Renamed method to a more appropriate name :) --- src/ScriptCs.Core/AssemblyResolver.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index 7341b83b..b66b40ad 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -16,7 +16,11 @@ public class AssemblyResolver : IAssemblyResolver private readonly IAssemblyUtility _assemblyUtility; - public AssemblyResolver(IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IAssemblyUtility assemblyUtility, ILog logger) + public AssemblyResolver( + IFileSystem fileSystem, + IPackageAssemblyResolver packageAssemblyResolver, + IAssemblyUtility assemblyUtility, + ILog logger) { _fileSystem = fileSystem; _packageAssemblyResolver = packageAssemblyResolver; @@ -29,12 +33,12 @@ public IEnumerable GetAssemblyPaths(string path) Guard.AgainstNullArgument("path", path); var packageAssemblies = GetPackageAssemblies(path); - var looseAssemblies = GetLooseAssemblies(path); + var binAssemblies = GetBinAssemblies(path); - return packageAssemblies.Union(looseAssemblies); + return packageAssemblies.Union(binAssemblies); } - private IEnumerable GetLooseAssemblies(string path) + private IEnumerable GetBinAssemblies(string path) { var binFolder = Path.Combine(path, Constants.BinFolder); if (!_fileSystem.DirectoryExists(binFolder)) From d46626a0b305d520456b80a0e227e3609356ce10 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:49:13 +0200 Subject: [PATCH 0306/1224] Added caching of assembly paths in AssemblyResolver --- src/ScriptCs.Core/AssemblyResolver.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index b66b40ad..b79fdbee 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -8,6 +8,8 @@ namespace ScriptCs { public class AssemblyResolver : IAssemblyResolver { + private static readonly Dictionary> AssemblyPathCache = new Dictionary>(); + private readonly IFileSystem _fileSystem; private readonly IPackageAssemblyResolver _packageAssemblyResolver; @@ -32,10 +34,16 @@ public IEnumerable GetAssemblyPaths(string path) { Guard.AgainstNullArgument("path", path); + List assemblies; + if (AssemblyPathCache.TryGetValue(path, out assemblies)) return assemblies; + var packageAssemblies = GetPackageAssemblies(path); var binAssemblies = GetBinAssemblies(path); - return packageAssemblies.Union(binAssemblies); + assemblies = packageAssemblies.Union(binAssemblies).ToList(); + AssemblyPathCache.Add(path, assemblies); + + return assemblies; } private IEnumerable GetBinAssemblies(string path) From c3f2403da9f1680eb2198ec2314e0cb88f60517c Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:55:05 +0200 Subject: [PATCH 0307/1224] Removed static cache because of failing tests --- src/ScriptCs.Core/AssemblyResolver.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index b79fdbee..c48cb3f0 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -8,7 +8,7 @@ namespace ScriptCs { public class AssemblyResolver : IAssemblyResolver { - private static readonly Dictionary> AssemblyPathCache = new Dictionary>(); + private readonly Dictionary> _assemblyPathCache = new Dictionary>(); private readonly IFileSystem _fileSystem; @@ -35,13 +35,13 @@ public IEnumerable GetAssemblyPaths(string path) Guard.AgainstNullArgument("path", path); List assemblies; - if (AssemblyPathCache.TryGetValue(path, out assemblies)) return assemblies; + if (_assemblyPathCache.TryGetValue(path, out assemblies)) return assemblies; var packageAssemblies = GetPackageAssemblies(path); var binAssemblies = GetBinAssemblies(path); assemblies = packageAssemblies.Union(binAssemblies).ToList(); - AssemblyPathCache.Add(path, assemblies); + _assemblyPathCache.Add(path, assemblies); return assemblies; } From 80388d023cbd0a4a6a18bb569e657440ba8597a9 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:59:51 +0200 Subject: [PATCH 0308/1224] Trigger CI build From d5a2ee84363cf3f0a45ae576c96dff044b60797e Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 8 Jun 2013 16:19:23 +0200 Subject: [PATCH 0309/1224] exported IConsole and ILog from Autofac to MEF Extensions --- src/ScriptCs/CompositionRoot.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 94d36a7f..0ed06d33 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -4,6 +4,7 @@ using Autofac; using Autofac.Integration.Mef; using Common.Logging; +using ScriptCs.Contracts; using ScriptCs.Engine.Roslyn; using ScriptCs.Package; using ScriptCs.Package.InstallationProvider; @@ -35,7 +36,8 @@ public void Initialize() loggerConfigurator.Configure(); var logger = loggerConfigurator.GetLogger(); - builder.RegisterInstance(logger); + builder.RegisterInstance(logger).Exported(x => x.As()); + builder.RegisterType().As().Exported(x => x.As()); var types = new[] { @@ -47,7 +49,6 @@ public void Initialize() typeof (ScriptPackResolver), typeof (NugetInstallationProvider), typeof (PackageInstaller), - typeof (ReplConsole), typeof (AssemblyName) }; From 12a04902594256b37be00ad80379a00ced39f071 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 9 Jun 2013 18:25:40 +0200 Subject: [PATCH 0310/1224] Fixed failing build after merge --- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 069360e1..c3363161 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using Common.Logging; using Moq; @@ -111,7 +112,7 @@ public void ShouldReturnErrorIfThereIsCompileException() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); @@ -146,7 +147,7 @@ public void ShouldReturnErrorIfThereIsExecuteException() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); From ca034fefb136c11e8969c78c3340ba8876e46513 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 10 Jun 2013 14:09:53 +0200 Subject: [PATCH 0311/1224] Increment version to v0.5.0 --- build/ScriptCs.Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 81cd5a30..67c61c08 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -9,7 +9,7 @@ - alpha + From bcb8f1f2860a316f48126d2874b9902620c82f77 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 10 Jun 2013 14:20:15 +0200 Subject: [PATCH 0312/1224] Incrementing version to v0.6.0-alpha --- build/ScriptCs.Version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 67c61c08..1fd5fc71 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -4,12 +4,12 @@ 0 - 5 + 6 0 - + alpha From 08565fbad2a46aa9e4634bc0a49945199b88aedf Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 11 Jun 2013 21:47:09 -0700 Subject: [PATCH 0313/1224] Opening up FilePreProcessor to make it extensible. Fix for #322 --- src/ScriptCs.Core/FilePreProcessor.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 4196aca1..3ed2d9f9 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -20,18 +20,18 @@ public FilePreProcessor(IFileSystem fileSystem, ILog logger) _logger = logger; } - public FilePreProcessorResult ProcessFile(string path) + public virtual FilePreProcessorResult ProcessFile(string path) { return Parse(context => ParseFile(path, context)); } - public FilePreProcessorResult ProcessScript(string script) + public virtual FilePreProcessorResult ProcessScript(string script) { var scriptLines = _fileSystem.SplitLines(script).ToList(); return Parse(context => ParseScript(scriptLines, context)); } - private FilePreProcessorResult Parse(Action parseAction) + protected virtual FilePreProcessorResult Parse(Action parseAction) { var context = new FilePreProcessorContext(); @@ -52,7 +52,7 @@ private FilePreProcessorResult Parse(Action parseAction }; } - private string GenerateCode(FilePreProcessorContext context) + protected string GenerateCode(FilePreProcessorContext context) { var stringBuilder = new StringBuilder(); @@ -71,7 +71,7 @@ private string GenerateCode(FilePreProcessorContext context) return stringBuilder.ToString(); } - private void ParseFile(string path, FilePreProcessorContext context) + protected void ParseFile(string path, FilePreProcessorContext context) { _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); @@ -80,7 +80,7 @@ private void ParseFile(string path, FilePreProcessorContext context) ParseScript(scriptLines, context, path); } - private void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) + protected void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) { // Insert line directive if there's a path if (path != null) InsertLineDirective(path, scriptLines); @@ -95,7 +95,7 @@ private void ParseScript(List scriptLines, FilePreProcessorContext conte if (path != null) context.LoadedScripts.Add(path); } - private static void InsertLineDirective(string path, List fileLines) + protected void InsertLineDirective(string path, List fileLines) { var bodyIndex = fileLines.FindIndex(line => PreProcessorUtil.IsNonDirectiveLine(line) && !PreProcessorUtil.IsUsingLine(line)); if (bodyIndex == -1) return; @@ -104,7 +104,7 @@ private static void InsertLineDirective(string path, List fileLines) fileLines.Insert(bodyIndex, directiveLine); } - private void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) + protected void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) { if (PreProcessorUtil.IsUsingLine(line)) { @@ -149,7 +149,7 @@ private void ProcessLine(FilePreProcessorContext context, string line, bool isBe context.Body.Add(line); } - private class FilePreProcessorContext + public class FilePreProcessorContext { public FilePreProcessorContext() { From 6b6be32ab4944880d60b52fbd34482d2e52803d7 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 11 Jun 2013 22:24:38 -0700 Subject: [PATCH 0314/1224] Making protected members virtual --- src/ScriptCs.Core/FilePreProcessor.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 3ed2d9f9..719937cb 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -52,7 +52,7 @@ protected virtual FilePreProcessorResult Parse(Action p }; } - protected string GenerateCode(FilePreProcessorContext context) + protected virtual string GenerateCode(FilePreProcessorContext context) { var stringBuilder = new StringBuilder(); @@ -71,7 +71,7 @@ protected string GenerateCode(FilePreProcessorContext context) return stringBuilder.ToString(); } - protected void ParseFile(string path, FilePreProcessorContext context) + protected virtual void ParseFile(string path, FilePreProcessorContext context) { _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); @@ -80,7 +80,7 @@ protected void ParseFile(string path, FilePreProcessorContext context) ParseScript(scriptLines, context, path); } - protected void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) + protected virtual void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) { // Insert line directive if there's a path if (path != null) InsertLineDirective(path, scriptLines); @@ -95,7 +95,7 @@ protected void ParseScript(List scriptLines, FilePreProcessorContext con if (path != null) context.LoadedScripts.Add(path); } - protected void InsertLineDirective(string path, List fileLines) + protected virtual void InsertLineDirective(string path, List fileLines) { var bodyIndex = fileLines.FindIndex(line => PreProcessorUtil.IsNonDirectiveLine(line) && !PreProcessorUtil.IsUsingLine(line)); if (bodyIndex == -1) return; @@ -104,7 +104,7 @@ protected void InsertLineDirective(string path, List fileLines) fileLines.Insert(bodyIndex, directiveLine); } - protected void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) + protected virtual void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) { if (PreProcessorUtil.IsUsingLine(line)) { From c6c3b646f9279355db5e5af478900531cf710169 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 15 Jun 2013 17:31:05 +0200 Subject: [PATCH 0315/1224] added ScriptCs/ScriptcsConsoleAppender.cs changed unnecessary info logging to debug REPL will now respect IConsole for logging output --- .../RoslynScriptEngine.cs | 6 ++--- src/ScriptCs/CompositionRoot.cs | 4 +-- src/ScriptCs/LoggerConfigurator.cs | 6 ++--- src/ScriptCs/Program.cs | 15 ++++++++--- src/ScriptCs/ScriptCs.csproj | 1 + src/ScriptCs/ScriptcsConsoleAppender.cs | 26 +++++++++++++++++++ 6 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 src/ScriptCs/ScriptcsConsoleAppender.cs diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 6ae75a46..245d0cd9 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -33,7 +33,7 @@ public ScriptResult Execute(string code, string[] scriptArgs, IEnumerable().As().Exported(x => x.As()); var loggerConfigurator = new LoggerConfigurator(_logLevel); - loggerConfigurator.Configure(); + loggerConfigurator.Configure(new ReplConsole()); var logger = loggerConfigurator.GetLogger(); builder.RegisterInstance(logger).Exported(x => x.As()); - builder.RegisterType().As().Exported(x => x.As()); var types = new[] { diff --git a/src/ScriptCs/LoggerConfigurator.cs b/src/ScriptCs/LoggerConfigurator.cs index c49399b3..bb2597a0 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/src/ScriptCs/LoggerConfigurator.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; +using ScriptCs.Contracts; using log4net; -using log4net.Appender; using log4net.Core; using log4net.Layout; using log4net.Repository.Hierarchy; @@ -25,11 +25,11 @@ public LoggerConfigurator(LogLevel logLevel) _logLevel = logLevel; } - public void Configure() + public void Configure(IConsole console) { var hierarchy = (Hierarchy)LogManager.GetRepository(); var logger = LogManager.GetLogger(LoggerName); - var consoleAppender = new ConsoleAppender + var consoleAppender = new ScriptcsConsoleAppender(console) { Layout = new PatternLayout(GetLogPattern(_logLevel)), Threshold = hierarchy.LevelMap[_logLevel.ToString().ToUpper(CultureInfo.CurrentCulture)] diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 9d555c38..cdced5ae 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -13,7 +13,7 @@ private static int Main(string[] args) string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - var commandArgs = ParseArguments(args) ?? new ScriptCsArgs { Repl = true }; + var commandArgs = ParseArguments(args); var compositionRoot = new CompositionRoot(commandArgs); compositionRoot.Initialize(); @@ -35,11 +35,20 @@ private static ScriptCsArgs ParseArguments(string[] args) { const string UnexpectedArgumentMessage = "Unexpected Argument: "; - if (args.Length <= 0) return null; + //no args initialized REPL + if (args.Length <= 0) return new ScriptCsArgs { Repl = true, LogLevel = LogLevel.Info}; try { - return Args.Parse(args); + var scriptcsArgs = Args.Parse(args); + + //if there is only 1 arg and it is a loglevel, it's also REPL + if (args.Length == 2 && args.Any(x => x.ToLowerInvariant() == "-log")) + { + scriptcsArgs.Repl = true; + } + + return scriptcsArgs; } catch (ArgException ex) { diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 5a735557..8a4d8b25 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -77,6 +77,7 @@ + diff --git a/src/ScriptCs/ScriptcsConsoleAppender.cs b/src/ScriptCs/ScriptcsConsoleAppender.cs new file mode 100644 index 00000000..f250e7f5 --- /dev/null +++ b/src/ScriptCs/ScriptcsConsoleAppender.cs @@ -0,0 +1,26 @@ +using System.Text; +using ScriptCs.Contracts; +using log4net.Appender; +using log4net.Core; + +namespace ScriptCs +{ + public class ScriptcsConsoleAppender : AppenderSkeleton + { + private readonly IConsole _console; + + public ScriptcsConsoleAppender(IConsole console) + { + _console = console; + } + + protected override void Append(LoggingEvent loggingEvent) + { + var txt = new StringBuilder(); + txt.Append(loggingEvent.Level); + txt.Append(": "); + txt.Append(loggingEvent.RenderedMessage); + _console.WriteLine(txt.ToString()); + } + } +} \ No newline at end of file From ecde0f2c8bf247f882bbd36e419c49b06cf14674 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 15 Jun 2013 15:09:19 -0600 Subject: [PATCH 0316/1224] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 738b6164..3a4dc65e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ We definitely want to soak up all that energy you have! ## The issue tracker and how you can contribute. * Bugs - For bugs, just go fix it. Don't ask UNLESS it starts to turn into a feature. -* Features - By default all issues tagged as enhancements will be fixed by the core team. However if you'd like to take it, please socialize the idea in our new google group (https://groups.google.com/forum/?fromgroups#!forum/scriptcs) so we can discuss before you put in a potentially wasted effort. +* Features - By default all issues tagged as enhancements which we file will be fixed by the core team. However if you'd like to take it, please comment in the issue that you'd like to implement it so we can discuss before you put in a potentially wasted effort. * YOU TAKE IT - These are items that are important, but which we'd available for the community to take. One place we use this is for investigations and prototyping for features that would be really awesome, but which the core team just don't have bandwith for. As an example @dschenkelman [investigated](https://github.com/scriptcs/scriptcs/issues/68?source=cc) a VS debugging story. This lead to him ultimately implementing the feature, however don't feel pressure that you have to that. It's extremely valuable if you can just show us how it might be done. A few other points: From c04912da92958663c6a1c1dafca856b855b262e7 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 15 Jun 2013 15:10:26 -0600 Subject: [PATCH 0317/1224] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 738b6164..3a4dc65e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ We definitely want to soak up all that energy you have! ## The issue tracker and how you can contribute. * Bugs - For bugs, just go fix it. Don't ask UNLESS it starts to turn into a feature. -* Features - By default all issues tagged as enhancements will be fixed by the core team. However if you'd like to take it, please socialize the idea in our new google group (https://groups.google.com/forum/?fromgroups#!forum/scriptcs) so we can discuss before you put in a potentially wasted effort. +* Features - By default all issues tagged as enhancements which we file will be fixed by the core team. However if you'd like to take it, please comment in the issue that you'd like to implement it so we can discuss before you put in a potentially wasted effort. * YOU TAKE IT - These are items that are important, but which we'd available for the community to take. One place we use this is for investigations and prototyping for features that would be really awesome, but which the core team just don't have bandwith for. As an example @dschenkelman [investigated](https://github.com/scriptcs/scriptcs/issues/68?source=cc) a VS debugging story. This lead to him ultimately implementing the feature, however don't feel pressure that you have to that. It's extremely valuable if you can just show us how it might be done. A few other points: From f2d61db1a8ab95af7a66b1c918d4bdefc4c7eb57 Mon Sep 17 00:00:00 2001 From: Michael Wade Date: Wed, 12 Jun 2013 12:43:17 +0100 Subject: [PATCH 0318/1224] Refs #321 scriptcs -install ScriptCs.AzureMobileServices * `GetWorkingDirectory` returns the current directory if the path is null/whitespace. * Fixed assumption that the directory/path would exist. * Added additional unit tests. --- src/ScriptCs.Core/FileSystem.cs | 16 ++++-- test/ScriptCs.Core.Tests/FileSystemTests.cs | 58 +++++++++++++++++++-- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index f96b8cdb..374d66ce 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -93,14 +93,22 @@ public Stream CreateFileStream(string filePath, FileMode mode) public string GetWorkingDirectory(string path) { + if (string.IsNullOrWhiteSpace(path)) + return CurrentDirectory; + var realPath = GetFullPath(path); - var attributes = File.GetAttributes(realPath); + if (FileExists(realPath) || DirectoryExists(realPath)) + { + var attributes = File.GetAttributes(realPath); - if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) - return realPath; - else + if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) + return realPath; + return Path.GetDirectoryName(realPath); + } + + return Path.GetDirectoryName(realPath); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs index f4004b37..f683eedf 100644 --- a/test/ScriptCs.Core.Tests/FileSystemTests.cs +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using Should; using Xunit; @@ -9,18 +10,18 @@ public class FileSystemTests { public class GetWorkingDirectoryMethod { + private readonly FileSystem _fileSystem = new FileSystem(); + [Fact] public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() { - const string pathToMyScriptFolder = @"..\my_script\"; + const string pathToMyScriptFolder = @"..\my_script"; try { Directory.CreateDirectory(pathToMyScriptFolder); - var fileSystem = new FileSystem(); - - fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + _fileSystem.GetWorkingDirectory(pathToMyScriptFolder) .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); } finally @@ -29,6 +30,55 @@ public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath Directory.Delete(pathToMyScriptFolder); } } + + [Fact] + public void ShouldReturnWorkingDirectoryIfPathIsInvalid() + { + var invalidPaths = new List {"", " ", null}; + + foreach (var invalidPath in invalidPaths) + { + _fileSystem.GetWorkingDirectory(invalidPath).ShouldEqual(_fileSystem.CurrentDirectory); + } + } + + [Fact] + public void ReturnsCorrectWorkingDirectory() + { + string workingDir = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @".\working_dir\")); + string existingDirectoryPath = Path.GetFullPath(Path.Combine(workingDir, @".\existing_dir\")); + string existingFilePath = Path.GetFullPath(Path.Combine(workingDir, @".\existing_file.txt")); + + try + { + Directory.CreateDirectory(workingDir); + Directory.CreateDirectory(existingDirectoryPath); + File.Create(existingFilePath).Dispose(); + + _fileSystem.GetWorkingDirectory(existingDirectoryPath).ShouldEqual(existingDirectoryPath); + _fileSystem.GetWorkingDirectory(existingFilePath).ShouldEqual( + Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @".\working_dir"))); + } + finally + { + if (Directory.Exists(existingDirectoryPath)) + Directory.Delete(existingDirectoryPath); + + if (File.Exists(existingFilePath)) + File.Delete(existingFilePath); + + if (Directory.Exists(workingDir)) + Directory.Delete(workingDir); + } + } + + [Fact] + public void ReturnsCorrectWorkingDirectoryIfPathDoesNotExist() + { + const string nonExistantFilePath = @"C:\working_dir\i_dont_exist.txt"; + + _fileSystem.GetWorkingDirectory(nonExistantFilePath).ShouldEqual(@"C:\working_dir"); + } } } } \ No newline at end of file From 0692cacd1a350d3538d8d5694d792749ddbfb61e Mon Sep 17 00:00:00 2001 From: Michael Wade Date: Wed, 12 Jun 2013 12:43:17 +0100 Subject: [PATCH 0319/1224] Refs #321 scriptcs -install ScriptCs.AzureMobileServices * `GetWorkingDirectory` returns the current directory if the path is null/whitespace. * Fixed assumption that the directory/path would exist. * Added additional unit tests. Fixes #321. --- src/ScriptCs.Core/FileSystem.cs | 16 ++++-- test/ScriptCs.Core.Tests/FileSystemTests.cs | 58 +++++++++++++++++++-- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 0d6bb702..4d657f33 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -88,14 +88,22 @@ public Stream CreateFileStream(string filePath, FileMode mode) public string GetWorkingDirectory(string path) { + if (string.IsNullOrWhiteSpace(path)) + return CurrentDirectory; + var realPath = GetFullPath(path); - var attributes = File.GetAttributes(realPath); + if (FileExists(realPath) || DirectoryExists(realPath)) + { + var attributes = File.GetAttributes(realPath); - if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) - return realPath; - else + if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) + return realPath; + return Path.GetDirectoryName(realPath); + } + + return Path.GetDirectoryName(realPath); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs index f4004b37..f683eedf 100644 --- a/test/ScriptCs.Core.Tests/FileSystemTests.cs +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using Should; using Xunit; @@ -9,18 +10,18 @@ public class FileSystemTests { public class GetWorkingDirectoryMethod { + private readonly FileSystem _fileSystem = new FileSystem(); + [Fact] public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() { - const string pathToMyScriptFolder = @"..\my_script\"; + const string pathToMyScriptFolder = @"..\my_script"; try { Directory.CreateDirectory(pathToMyScriptFolder); - var fileSystem = new FileSystem(); - - fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + _fileSystem.GetWorkingDirectory(pathToMyScriptFolder) .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); } finally @@ -29,6 +30,55 @@ public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath Directory.Delete(pathToMyScriptFolder); } } + + [Fact] + public void ShouldReturnWorkingDirectoryIfPathIsInvalid() + { + var invalidPaths = new List {"", " ", null}; + + foreach (var invalidPath in invalidPaths) + { + _fileSystem.GetWorkingDirectory(invalidPath).ShouldEqual(_fileSystem.CurrentDirectory); + } + } + + [Fact] + public void ReturnsCorrectWorkingDirectory() + { + string workingDir = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @".\working_dir\")); + string existingDirectoryPath = Path.GetFullPath(Path.Combine(workingDir, @".\existing_dir\")); + string existingFilePath = Path.GetFullPath(Path.Combine(workingDir, @".\existing_file.txt")); + + try + { + Directory.CreateDirectory(workingDir); + Directory.CreateDirectory(existingDirectoryPath); + File.Create(existingFilePath).Dispose(); + + _fileSystem.GetWorkingDirectory(existingDirectoryPath).ShouldEqual(existingDirectoryPath); + _fileSystem.GetWorkingDirectory(existingFilePath).ShouldEqual( + Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @".\working_dir"))); + } + finally + { + if (Directory.Exists(existingDirectoryPath)) + Directory.Delete(existingDirectoryPath); + + if (File.Exists(existingFilePath)) + File.Delete(existingFilePath); + + if (Directory.Exists(workingDir)) + Directory.Delete(workingDir); + } + } + + [Fact] + public void ReturnsCorrectWorkingDirectoryIfPathDoesNotExist() + { + const string nonExistantFilePath = @"C:\working_dir\i_dont_exist.txt"; + + _fileSystem.GetWorkingDirectory(nonExistantFilePath).ShouldEqual(@"C:\working_dir"); + } } } } \ No newline at end of file From d31db4c7661eda2bcbc9f39e8a70f5f1bea1e1be Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 16 Jun 2013 18:52:33 -0400 Subject: [PATCH 0320/1224] Increment version to v0.5.1 --- build/ScriptCs.Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 67c61c08..84963c56 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -5,7 +5,7 @@ 0 5 - 0 + 1 From 643a82ac6b4289e79700e9b9b1a942645537762e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 20:03:06 +0200 Subject: [PATCH 0321/1224] Added AutoFixture.AutoMoq --- test/ScriptCs.Tests/ScriptCs.Tests.csproj | 7 +++++++ test/ScriptCs.Tests/app.config | 15 +++++++++++++++ test/ScriptCs.Tests/packages.config | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 test/ScriptCs.Tests/app.config diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 7a0b535e..4c4d6d25 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -16,6 +16,12 @@ ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll + + ..\..\packages\AutoFixture.3.2.0\lib\net40\Ploeh.AutoFixture.dll + + + ..\..\packages\AutoFixture.AutoMoq.3.2.0\lib\net40\Ploeh.AutoFixture.AutoMoq.dll + ..\..\packages\Should.1.1.12.0\lib\Should.dll @@ -68,6 +74,7 @@ + diff --git a/test/ScriptCs.Tests/app.config b/test/ScriptCs.Tests/app.config new file mode 100644 index 00000000..9547ab7c --- /dev/null +++ b/test/ScriptCs.Tests/app.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/ScriptCs.Tests/packages.config b/test/ScriptCs.Tests/packages.config index 667f949f..ffaabf30 100644 --- a/test/ScriptCs.Tests/packages.config +++ b/test/ScriptCs.Tests/packages.config @@ -1,5 +1,7 @@  + + From 826962699d6addaec965319d8e766374864febbf Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 20:48:56 +0200 Subject: [PATCH 0322/1224] Refactored command tests to use Autofixture for cleaner, less brittle tests. --- test/ScriptCs.Tests/CleanCommandTests.cs | 99 ++++++++++++++++--- test/ScriptCs.Tests/CommandFactoryTests.cs | 25 +++-- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 22 ++--- .../ExecuteScriptCommandTests.cs | 66 ++++++------- test/ScriptCs.Tests/InstallCommandTests.cs | 36 +++---- test/ScriptCs.Tests/ScriptArgsTests.cs | 55 +++++------ test/ScriptCs.Tests/VersionCommandTests.cs | 51 +++++----- 7 files changed, 203 insertions(+), 151 deletions(-) diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 62553def..92e4b40a 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,7 +1,10 @@ -using Common.Logging; +using System; using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; -using ScriptCs.Package; using Xunit; namespace ScriptCs.Tests @@ -15,20 +18,16 @@ public void ShouldDeletePackagesFolder() { var args = new ScriptCsArgs { Clean = true }; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + fixture.Register(() => fs.Object); + + var root = fixture.Create(); + var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -37,6 +36,82 @@ public void ShouldDeletePackagesFolder() fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); } + + [Fact] + public void ShouldDeleteBinFolder() + { + var args = new ScriptCsArgs { Clean = true }; + + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + + var fs = new Mock(); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + + fixture.Register(() => fs.Object); + + var root = fixture.Create(); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + result.Execute(); + + fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + } + + [Fact] + public void ShouldNotDeleteBinFolderIfDllsAreLeft() + { + var args = new ScriptCsArgs { Clean = true }; + + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + + var fs = new Mock(); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); + fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); + + fixture.Register(() => fs.Object); + + var root = fixture.Create(); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + result.Execute(); + + fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); + } + + [Fact] + public void ShouldDeleteAllFilesResolvedFromPackages() + { + var args = new ScriptCsArgs { Clean = true }; + + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + + var fs = new Mock(); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); + + var resolver = new Mock(); + resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); + + fixture.Register(() => fs.Object); + fixture.Register(() => resolver.Object); + + var root = fixture.Create(); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + result.Execute(); + + fs.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); + } } } } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 353d9030..574b3bd1 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -1,7 +1,10 @@ -using Common.Logging; -using Moq; +using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; -using ScriptCs.Package; + using Should; using Xunit; @@ -17,22 +20,16 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool const string PackagesFile = "C:\\packages.config"; const string PackagesFolder = "C:\\packages"; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); fs.Setup(x => x.FileExists(PackagesFile)).Returns(packagesFileExists); fs.Setup(x => x.DirectoryExists(PackagesFolder)).Returns(packagesFolderExists); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - return root; + fixture.Register(() => fs.Object); + + return fixture.Create(); } [Fact] diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index d86e3ed0..0724bad2 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -3,6 +3,10 @@ using System.Text; using Common.Logging; using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; using ScriptCs.Contracts; using ScriptCs.Package; @@ -17,8 +21,11 @@ public class TheExecuteMethod [Fact] public void ShouldPromptForInput() { + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var mockFileSystem = new Mock(); mockFileSystem.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + fixture.Register(() => mockFileSystem.Object); var builder = new StringBuilder(); @@ -26,18 +33,9 @@ public void ShouldPromptForInput() var writer = new StringWriter(builder); var console = new FakeConsole(writer, reader); + fixture.Register(() => console); - var root = new ScriptServiceRoot( - mockFileSystem.Object, - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - console); + var root = fixture.Create(); var commandFactory = new CommandFactory(root); @@ -91,4 +89,4 @@ public void ResetColor() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c3363161..765ab08a 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,11 +1,15 @@ using System; using System.Collections.Generic; using System.IO; -using Common.Logging; + using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; using ScriptCs.Contracts; -using ScriptCs.Package; + using Xunit; using System.Linq; @@ -25,18 +29,16 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() ScriptName = "test.csx" }; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + fixture.Register(() => fs.Object); - var resolver = new Mock(); var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fixture.Register(() => executor.Object); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -60,25 +62,15 @@ public void NonManagedAssembliesAreExcluded() ScriptName = "test.csx" }; - var fs = new Mock(); - fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(new[] { - "managed.dll", - nonManaged - }); - - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(WorkingDirectory); + fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); + fixture.Register(() => fs.Object); + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -134,21 +126,23 @@ public void ShouldReturnErrorIfThereIsExecuteException() ScriptName = "test.csx" }; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + fixture.Register(() => fs.Object); - var resolver = new Mock(); - var executor = new Mock(); executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) .Returns(new ScriptResult { ExecuteException = new Exception("test") }); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assemblyName = new Mock(); + assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); + fixture.Register(() => assemblyName.Object); + + var executor = new Mock(); + fixture.Register(() => executor.Object); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index c1e4efaa..a9efe01b 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -4,6 +4,10 @@ using System.Runtime.Versioning; using Common.Logging; using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; using ScriptCs.Package; using Xunit; @@ -26,19 +30,17 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() const string CurrentDirectory = @"C:\"; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fixture.Register(() => fs.Object); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fixture.Register(() => packageInstaller.Object); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -60,25 +62,25 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() const string CurrentDirectory = @"C:\"; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fixture.Register(() => fs.Object); var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { new PackageReference("a", new FrameworkName(".NETFramework,Version=v4.0"), new Version()), new PackageReference("b", new FrameworkName(".NETFramework,Version=v4.0"), new Version()) }); + fixture.Register(() => resolver.Object); + + var packageInstaller = new Mock(); + fixture.Register(() => packageInstaller.Object); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); diff --git a/test/ScriptCs.Tests/ScriptArgsTests.cs b/test/ScriptCs.Tests/ScriptArgsTests.cs index 10e8f5b8..b5954a8c 100644 --- a/test/ScriptCs.Tests/ScriptArgsTests.cs +++ b/test/ScriptCs.Tests/ScriptArgsTests.cs @@ -1,8 +1,5 @@ -using System; -using Common.Logging; -using Moq; -using ScriptCs.Command; -using ScriptCs.Package; +using Should; + using Xunit; namespace ScriptCs.Tests @@ -19,88 +16,80 @@ public void ShouldHandleEmptyArgs() ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[0], args); - Assert.Equal(new string[0], scriptArgs); + args.ShouldEqual(new string[0]); + scriptArgs.ShouldEqual(new string[0]); } [Fact] public void ShouldHandleMissingDoubledash() { - string[] args = new string[] { "scriptname.csx", "-restore" }; + string[] args = new[] { "scriptname.csx", "-restore" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); - Assert.Equal(new string[0], scriptArgs); + args.ShouldEqual(new[] { "scriptname.csx", "-restore" }); + scriptArgs.ShouldEqual(new string[0]); } [Fact] public void ShouldHandleArgsAndScriptArgs() { - string[] args = new string[] { "scriptname.csx", "-restore", "--", "-port", "8080" }; + string[] args = new[] { "scriptname.csx", "-restore", "--", "-port", "8080" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); - Assert.Equal(new string[] { "-port", "8080" }, scriptArgs); + args.ShouldEqual(new[] { "scriptname.csx", "-restore" }); + scriptArgs.ShouldEqual(new[] { "-port", "8080" }); } [Fact] public void ShouldHandleJustScriptArgs() { - string[] args = new string[] { "--", "-port", "8080" }; + string[] args = new[] { "--", "-port", "8080" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[0], args); - Assert.Equal(new string[] { "-port", "8080" }, scriptArgs); + args.ShouldEqual(new string[0]); + scriptArgs.ShouldEqual(new[] { "-port", "8080" }); } [Fact] public void ShouldHandleJustDoubledash() { - string[] args = new string[] { "--" }; + string[] args = new[] { "--" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[0], args); - Assert.Equal(new string[0], scriptArgs); + args.ShouldEqual(new string[0]); + scriptArgs.ShouldEqual(new string[0]); } [Fact] public void ShouldHandleExtraDoubledash() { - string[] args = new string[] { "scriptname.csx", "-restore", "--", "-port", "--", "8080" }; + string[] args = new[] { "scriptname.csx", "-restore", "--", "-port", "--", "8080" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); - Assert.Equal(new string[] { "-port", "--", "8080" }, scriptArgs); + args.ShouldEqual(new[] { "scriptname.csx", "-restore" }); + scriptArgs.ShouldEqual(new[] { "-port", "--", "8080" }); } [Fact] public void ShouldHandleTrailingDoubledash() { - string[] args = new string[] { "scriptname.csx", "-restore", "--" }; + string[] args = new[] { "scriptname.csx", "-restore", "--" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); - Assert.Equal(new string[0], scriptArgs); - } - - public class ScriptArgsPlumbing { - [Fact] - public void ScriptArgsArePlumbedThrough() - { - - } + args.ShouldEqual(new[] { "scriptname.csx", "-restore" }); + scriptArgs.ShouldEqual(new string[0]); } } } diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 8546f5e8..724fa09e 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -1,8 +1,16 @@ -using Common.Logging; -using Moq; +using System; +using System.Reflection; +using System.Text; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; -using ScriptCs.Package; + using System.IO; + +using Should; + using Xunit; namespace ScriptCs.Tests @@ -11,39 +19,28 @@ public class VersionCommandTests { public class ExecuteMethod { - private readonly System.Version _currentVersion; + private readonly Version _currentVersion; + + private readonly StringBuilder _outputText; - System.Text.StringBuilder _outputText; - StringWriter _mockConsole; - TextWriter _actualConsole; + private readonly StringWriter _mockConsole; public ExecuteMethod() { - _currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - _outputText = new System.Text.StringBuilder(); + _currentVersion = Assembly.GetExecutingAssembly().GetName().Version; + _outputText = new StringBuilder(); _mockConsole = new StringWriter(_outputText); - _actualConsole = System.Console.Out; - System.Console.SetOut(_mockConsole); + Console.SetOut(_mockConsole); } [Fact] public void VersionCommandShouldOutputVersion() { - var args = new ScriptCsArgs - { - Version = true - }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var args = new ScriptCsArgs { Version = true }; + + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -53,7 +50,7 @@ public void VersionCommandShouldOutputVersion() result.Execute(); - Assert.Contains("scriptcs version " + _currentVersion.ToString(), _outputText.ToString()); + _outputText.ToString().ShouldContain("scriptcs version " + _currentVersion); } } } From da224d7811b03e80e955f9d7f061e0bb85489d03 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 22:25:52 +0200 Subject: [PATCH 0323/1224] Cleaned up most tests to a simple AAA pattern --- test/ScriptCs.Tests/CleanCommandTests.cs | 119 +++++-------- .../ExecuteScriptCommandTests.cs | 160 +++++------------- test/ScriptCs.Tests/InstallCommandTests.cs | 100 +++++------ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 7 + .../ScriptCsAutoDataAttribute.cs | 13 ++ test/ScriptCs.Tests/VersionCommandTests.cs | 24 +-- test/ScriptCs.Tests/app.config | 4 + test/ScriptCs.Tests/packages.config | 2 + 8 files changed, 166 insertions(+), 263 deletions(-) create mode 100644 test/ScriptCs.Tests/ScriptCsAutoDataAttribute.cs diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 92e4b40a..472025f9 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,11 +1,11 @@ using System; using Moq; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Command; -using Xunit; + +using Xunit.Extensions; namespace ScriptCs.Tests { @@ -13,104 +13,77 @@ public class CleanCommandTests { public class ExecuteMethod { - [Fact] - public void ShouldDeletePackagesFolder() + [Theory, ScriptCsAutoData] + public void ShouldDeletePackagesFolder([Frozen] Mock fileSystem, CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Clean = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - - fixture.Register(() => fs.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); + fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); + fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); + // Assert + fileSystem.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); + fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); } - [Fact] - public void ShouldDeleteBinFolder() + [Theory, ScriptCsAutoData] + public void ShouldDeleteBinFolder([Frozen] Mock fileSystem, CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Clean = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - - fixture.Register(() => fs.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); + fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + // Assert + fileSystem.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); } - [Fact] - public void ShouldNotDeleteBinFolderIfDllsAreLeft() + [Theory, ScriptCsAutoData] + public void ShouldNotDeleteBinFolderIfDllsAreLeft([Frozen] Mock fileSystem, CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Clean = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); + fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); + fileSystem.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); - var fs = new Mock(); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); - fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - fixture.Register(() => fs.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); + // Assert + fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); } - [Fact] - public void ShouldDeleteAllFilesResolvedFromPackages() + [Theory, ScriptCsAutoData] + public void ShouldDeleteAllFilesResolvedFromPackages( + [Frozen] Mock fileSystem, + [Frozen] Mock resolver, + CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Clean = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); + fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + fileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(true); - var fs = new Mock(); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); - - var resolver = new Mock(); resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); - fixture.Register(() => fs.Object); - fixture.Register(() => resolver.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - fs.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); + // Assert + fileSystem.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); } } } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 765ab08a..b47f554c 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -4,153 +4,87 @@ using Moq; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Command; using ScriptCs.Contracts; -using Xunit; using System.Linq; +using Xunit.Extensions; + namespace ScriptCs.Tests { public class ExecuteScriptCommandTests { public class ExecuteMethod { - [Fact] - public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() - { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = "test.csx" - }; - - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fixture.Register(() => fs.Object); - - var executor = new Mock(); - fixture.Register(() => executor.Object); + private const string CurrentDirectory = "C:\\"; - var root = fixture.Create(); + [Theory, ScriptCsAutoData] + public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs( + [Frozen] Mock fileSystem, + [Frozen] Mock executor, + CommandFactory factory) + { + // Arrange + var args = new ScriptCsArgs { AllowPreRelease = false, Install = "", ScriptName = "test.csx" }; - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); + // Assert executor.Verify(i => i.Initialize(It.IsAny>(), It.IsAny>()), Times.Once()); executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); executor.Verify(i => i.Terminate(), Times.Once()); } - [Fact] - public void NonManagedAssembliesAreExcluded() + [Theory, ScriptCsAutoData] + public void ShouldCreateMissingBinFolder([Frozen] Mock fileSystem, CommandFactory factory) { - const string nonManaged = "non-managed.dll"; - - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = "test.csx" - }; - - var fixture = new Fixture().Customize(new AutoMoqCustomization()); + // Arrange + var binFolder = Path.Combine(CurrentDirectory, Constants.BinFolder); - var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(WorkingDirectory); - fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); - fixture.Register(() => fs.Object); + var args = new ScriptCsArgs { ScriptName = "test.csx" }; - var root = fixture.Create(); - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); + fileSystem.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fileSystem.Setup(x => x.DirectoryExists(binFolder)).Returns(false); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - executor.Verify(i => i.Initialize(It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); - executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); - executor.Verify(i => i.Terminate(), Times.Once()); + // Assert + fileSystem.Verify(x => x.CreateDirectory(binFolder), Times.Once()); } - [Fact] - public void ShouldReturnErrorIfThereIsCompileException() + [Theory, ScriptCsAutoData] + public void NonManagedAssembliesAreExcluded( + [Frozen] Mock fileSystem, + [Frozen] Mock assemblyName, + [Frozen] Mock executor, + CommandFactory factory) { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = "test.csx" - }; - - var fs = new Mock(); - fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - - var resolver = new Mock(); - var executor = new Mock(); - executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) - .Returns(new ScriptResult {CompileException = new Exception("test")}); - - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - var commandResult = result.Execute(); - - Assert.Equal(CommandResult.Error, commandResult); - logger.Verify(i => i.Error(It.IsAny()),Times.Once()); - } - - [Fact] - public void ShouldReturnErrorIfThereIsExecuteException() - { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = "test.csx" - }; - - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fixture.Register(() => fs.Object); + // Arrange + const string NonManaged = "non-managed.dll"; - executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) - .Returns(new ScriptResult { ExecuteException = new Exception("test") }); + var args = new ScriptCsArgs { AllowPreRelease = false, Install = "", ScriptName = "test.csx" }; - var assemblyName = new Mock(); - assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); - fixture.Register(() => assemblyName.Object); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fileSystem.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())) + .Returns(new[] { "managed.dll", NonManaged }); - var executor = new Mock(); - fixture.Register(() => executor.Object); + assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == NonManaged))).Throws(new BadImageFormatException()); - var root = fixture.Create(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - var commandResult = result.Execute(); - - Assert.Equal(CommandResult.Error, commandResult); - logger.Verify(i => i.Error(It.IsAny()), Times.Once()); + // Assert + executor.Verify(i => i.Initialize(It.Is>(x => !x.Contains(NonManaged)), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); + executor.Verify(i => i.Terminate(), Times.Once()); } } } diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index a9efe01b..c38837f7 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -2,15 +2,15 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.Versioning; -using Common.Logging; + using Moq; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Command; using ScriptCs.Package; -using Xunit; + +using Xunit.Extensions; namespace ScriptCs.Tests { @@ -18,75 +18,55 @@ public class InstallCommandTests { public class ExecuteMethod { - [Fact] - public void InstallCommandShouldInstallSinglePackageIfNamePassed() - { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "mypackage", - ScriptName = null - }; - - const string CurrentDirectory = @"C:\"; - - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - fixture.Register(() => fs.Object); - - var packageInstaller = new Mock(); - fixture.Register(() => packageInstaller.Object); - - var root = fixture.Create(); + private const string CurrentDirectory = @"C:\"; - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - packageInstaller.Verify(i => i.InstallPackages(It.Is>(x => x.Count() == 1 && x.First().PackageId == "mypackage"), It.IsAny(), It.IsAny>()), Times.Once()); + [Theory, ScriptCsAutoData] + public void InstallCommandShouldInstallSinglePackageIfNamePassed( + [Frozen] Mock fileSystem, + [Frozen] Mock packageInstaller, + CommandFactory factory) + { + // Arrange + var args = new ScriptCsArgs { AllowPreRelease = false, Install = "mypackage", ScriptName = null }; + + fileSystem.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + + // Act + factory.CreateCommand(args, new string[0]).Execute(); + + // Assert + packageInstaller.Verify(i => + i.InstallPackages( + It.Is>(x => x.Count() == 1 && x.First().PackageId == "mypackage"), + It.IsAny(), + It.IsAny>()), + Times.Once()); } - [Fact] - public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() + [Theory, ScriptCsAutoData] + public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed( + [Frozen] Mock fileSystem, + [Frozen] Mock resolver, + [Frozen] Mock packageInstaller, + CommandFactory factory) { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = null - }; - - const string CurrentDirectory = @"C:\"; + // Arrange + var args = new ScriptCsArgs { AllowPreRelease = false, Install = "", ScriptName = null }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); + fileSystem.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - fixture.Register(() => fs.Object); - - var resolver = new Mock(); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { new PackageReference("a", new FrameworkName(".NETFramework,Version=v4.0"), new Version()), new PackageReference("b", new FrameworkName(".NETFramework,Version=v4.0"), new Version()) }); - fixture.Register(() => resolver.Object); - - var packageInstaller = new Mock(); - fixture.Register(() => packageInstaller.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); + // Assert packageInstaller.Verify(i => i.InstallPackages(It.Is>(x => x.Count() == 2), It.IsAny(), It.IsAny>()), Times.Once()); } } diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 4c4d6d25..27f555ed 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -22,6 +22,9 @@ ..\..\packages\AutoFixture.AutoMoq.3.2.0\lib\net40\Ploeh.AutoFixture.AutoMoq.dll + + ..\..\packages\AutoFixture.Xunit.3.2.0\lib\net40\Ploeh.AutoFixture.Xunit.dll + ..\..\packages\Should.1.1.12.0\lib\Should.dll @@ -38,6 +41,9 @@ ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + ..\..\packages\xunit.extensions.1.9.1\lib\net20\xunit.extensions.dll + @@ -50,6 +56,7 @@ + diff --git a/test/ScriptCs.Tests/ScriptCsAutoDataAttribute.cs b/test/ScriptCs.Tests/ScriptCsAutoDataAttribute.cs new file mode 100644 index 00000000..9963884a --- /dev/null +++ b/test/ScriptCs.Tests/ScriptCsAutoDataAttribute.cs @@ -0,0 +1,13 @@ +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; + +namespace ScriptCs.Tests +{ + public class ScriptCsAutoDataAttribute : AutoDataAttribute + { + public ScriptCsAutoDataAttribute() : this(new Fixture()) { } + + private ScriptCsAutoDataAttribute(IFixture fixture) : base(fixture.Customize(new AutoMoqCustomization())) { } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 724fa09e..8e4fbd6b 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -2,16 +2,13 @@ using System.Reflection; using System.Text; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; - using ScriptCs.Command; using System.IO; using Should; -using Xunit; +using Xunit.Extensions; namespace ScriptCs.Tests { @@ -33,23 +30,16 @@ public ExecuteMethod() Console.SetOut(_mockConsole); } - [Fact] - public void VersionCommandShouldOutputVersion() + [Theory, ScriptCsAutoData] + public void VersionCommandShouldOutputVersion(CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Version = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - // clear the fake console output - _outputText.Clear(); - - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); + // Assert _outputText.ToString().ShouldContain("scriptcs version " + _currentVersion); } } diff --git a/test/ScriptCs.Tests/app.config b/test/ScriptCs.Tests/app.config index 9547ab7c..7af0e182 100644 --- a/test/ScriptCs.Tests/app.config +++ b/test/ScriptCs.Tests/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/test/ScriptCs.Tests/packages.config b/test/ScriptCs.Tests/packages.config index ffaabf30..cebb9a12 100644 --- a/test/ScriptCs.Tests/packages.config +++ b/test/ScriptCs.Tests/packages.config @@ -2,8 +2,10 @@ + + \ No newline at end of file From ada56c0c2aea44d94f83c53ab0595008c8d6b292 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 22:29:22 +0200 Subject: [PATCH 0324/1224] Refactored VersionCommand and test to use IConsole --- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/Command/VersionCommand.cs | 15 +++++++++-- test/ScriptCs.Tests/VersionCommandTests.cs | 30 ++++++---------------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index f322affb..abb46bfd 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -107,7 +107,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Version) { - return new VersionCommand(); + return new VersionCommand(_scriptServiceRoot.Console); } return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: false); diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index d51b4a0a..ab614434 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -1,12 +1,23 @@ -using System; +using System.Reflection; + +using ScriptCs.Contracts; namespace ScriptCs.Command { internal class VersionCommand : IVersionCommand { + private readonly IConsole _console; + + public VersionCommand(IConsole console) + { + _console = console; + } + public CommandResult Execute() { - Console.WriteLine("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + var version = Assembly.GetExecutingAssembly().GetName().Version; + _console.WriteLine(string.Format("scriptcs version {0}", version)); + return CommandResult.Success; } } diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 8e4fbd6b..52eab82f 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -1,12 +1,11 @@ -using System; -using System.Reflection; -using System.Text; +using System.Reflection; -using ScriptCs.Command; +using Moq; -using System.IO; +using Ploeh.AutoFixture.Xunit; -using Should; +using ScriptCs.Command; +using ScriptCs.Contracts; using Xunit.Extensions; @@ -16,31 +15,18 @@ public class VersionCommandTests { public class ExecuteMethod { - private readonly Version _currentVersion; - - private readonly StringBuilder _outputText; - - private readonly StringWriter _mockConsole; - - public ExecuteMethod() - { - _currentVersion = Assembly.GetExecutingAssembly().GetName().Version; - _outputText = new StringBuilder(); - _mockConsole = new StringWriter(_outputText); - Console.SetOut(_mockConsole); - } - [Theory, ScriptCsAutoData] - public void VersionCommandShouldOutputVersion(CommandFactory factory) + public void VersionCommandShouldOutputVersion([Frozen] Mock console, CommandFactory factory) { // Arrange var args = new ScriptCsArgs { Version = true }; + var currentVersion = Assembly.GetExecutingAssembly().GetName().Version; // Act factory.CreateCommand(args, new string[0]).Execute(); // Assert - _outputText.ToString().ShouldContain("scriptcs version " + _currentVersion); + console.Verify(x => x.WriteLine("scriptcs version " + currentVersion)); } } } From a28ec0fae09200aead2816c95a461384459b5b22 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 22:47:51 +0200 Subject: [PATCH 0325/1224] Slimmed down ExecuteReplCommandTest by using mocks instead of fake class --- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 83 ++++--------------- 1 file changed, 17 insertions(+), 66 deletions(-) diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index 0724bad2..1cad3c93 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -1,16 +1,13 @@ using System; -using System.IO; using System.Text; -using Common.Logging; using Moq; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Command; using ScriptCs.Contracts; -using ScriptCs.Package; using Xunit; +using Xunit.Extensions; namespace ScriptCs.Tests { @@ -18,74 +15,28 @@ public class ExecuteReplCommandTests { public class TheExecuteMethod { - [Fact] - public void ShouldPromptForInput() + [Theory, ScriptCsAutoData] + public void ShouldPromptForInput( + [Frozen] Mock fileSystem, + [Frozen] Mock console, + CommandFactory factory) { - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var mockFileSystem = new Mock(); - mockFileSystem.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fixture.Register(() => mockFileSystem.Object); - + // Arrange + var readLines = 0; var builder = new StringBuilder(); + var args = new ScriptCsArgs { Repl = true }; - var reader = new StringReader(Environment.NewLine); - var writer = new StringWriter(builder); - - var console = new FakeConsole(writer, reader); - fixture.Register(() => console); - - var root = fixture.Create(); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - var commandFactory = new CommandFactory(root); + console.Setup(x => x.ReadLine()).Returns(() => string.Empty).Callback(() => readLines++); + console.Setup(x => x.Write(It.IsAny())).Callback(value => builder.Append(value)); - var target = commandFactory.CreateCommand(new ScriptCsArgs { Repl = true }, new string[0]); - - target.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); + // Assert Assert.True(builder.ToString().EndsWith("> ")); - Assert.Equal(1, console.ReadLineCounter); - } - } - - public class FakeConsole : IConsole - { - private readonly TextWriter writer; - private readonly TextReader reader; - - public FakeConsole(TextWriter textWriter, TextReader textReader) - { - writer = textWriter; - reader = textReader; - ReadLineCounter = 0; - } - - public ConsoleColor ForegroundColor { get; set; } - - public int ReadLineCounter { get; set; } - - public void Write(string value) - { - writer.Write(value); - } - - public void WriteLine(string value) - { - writer.WriteLine(value); - } - - public string ReadLine() - { - ReadLineCounter++; - return reader.ReadLine(); - } - - public void Exit() - { - } - - public void ResetColor() - { + Assert.Equal(1, readLines); } } } From 234b07b0dceec5c7952637a27acdf37c68fd22c8 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 9 Jun 2013 18:27:05 +0200 Subject: [PATCH 0326/1224] Fixed failing build after merge --- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index b47f554c..e91c015f 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; +using Common.Logging; + using Moq; using Ploeh.AutoFixture.Xunit; @@ -11,6 +13,9 @@ using System.Linq; +using ScriptCs.Package; + +using Xunit; using Xunit.Extensions; namespace ScriptCs.Tests From 330b1baf5211bcef25bd04f7d575cb9864280552 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 17 Jun 2013 01:43:49 +0200 Subject: [PATCH 0327/1224] Fixed build and removed old tests for CleanCommand and ExecuteScriptCommand. --- test/ScriptCs.Tests/CleanCommandTests.cs | 59 +------------------ .../ExecuteScriptCommandTests.cs | 33 ++--------- 2 files changed, 5 insertions(+), 87 deletions(-) diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 472025f9..6ac464d7 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,5 +1,4 @@ -using System; -using Moq; +using Moq; using Ploeh.AutoFixture.Xunit; @@ -29,62 +28,6 @@ public void ShouldDeletePackagesFolder([Frozen] Mock fileSystem, Co fileSystem.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); } - - [Theory, ScriptCsAutoData] - public void ShouldDeleteBinFolder([Frozen] Mock fileSystem, CommandFactory factory) - { - // Arrange - var args = new ScriptCsArgs { Clean = true }; - - fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - - // Act - factory.CreateCommand(args, new string[0]).Execute(); - - // Assert - fileSystem.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - } - - [Theory, ScriptCsAutoData] - public void ShouldNotDeleteBinFolderIfDllsAreLeft([Frozen] Mock fileSystem, CommandFactory factory) - { - // Arrange - var args = new ScriptCsArgs { Clean = true }; - - fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); - fileSystem.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); - - // Act - factory.CreateCommand(args, new string[0]).Execute(); - - // Assert - fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); - } - - [Theory, ScriptCsAutoData] - public void ShouldDeleteAllFilesResolvedFromPackages( - [Frozen] Mock fileSystem, - [Frozen] Mock resolver, - CommandFactory factory) - { - // Arrange - var args = new ScriptCsArgs { Clean = true }; - - fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - fileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(true); - - resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); - - // Act - factory.CreateCommand(args, new string[0]).Execute(); - - // Assert - fileSystem.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); - } } } } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index e91c015f..ccff00d7 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using Common.Logging; - using Moq; using Ploeh.AutoFixture.Xunit; @@ -13,9 +10,6 @@ using System.Linq; -using ScriptCs.Package; - -using Xunit; using Xunit.Extensions; namespace ScriptCs.Tests @@ -46,29 +40,10 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs( executor.Verify(i => i.Terminate(), Times.Once()); } - [Theory, ScriptCsAutoData] - public void ShouldCreateMissingBinFolder([Frozen] Mock fileSystem, CommandFactory factory) - { - // Arrange - var binFolder = Path.Combine(CurrentDirectory, Constants.BinFolder); - - var args = new ScriptCsArgs { ScriptName = "test.csx" }; - - fileSystem.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - fileSystem.Setup(x => x.DirectoryExists(binFolder)).Returns(false); - - // Act - factory.CreateCommand(args, new string[0]).Execute(); - - // Assert - fileSystem.Verify(x => x.CreateDirectory(binFolder), Times.Once()); - } - [Theory, ScriptCsAutoData] public void NonManagedAssembliesAreExcluded( [Frozen] Mock fileSystem, - [Frozen] Mock assemblyName, + [Frozen] Mock assemblyUtility, [Frozen] Mock executor, CommandFactory factory) { @@ -78,10 +53,10 @@ public void NonManagedAssembliesAreExcluded( var args = new ScriptCsArgs { AllowPreRelease = false, Install = "", ScriptName = "test.csx" }; fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - fileSystem.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())) + fileSystem.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)) .Returns(new[] { "managed.dll", NonManaged }); - assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == NonManaged))).Throws(new BadImageFormatException()); + assemblyUtility.Setup(x => x.IsManagedAssembly(It.Is(y => y == NonManaged))).Returns(false); // Act factory.CreateCommand(args, new string[0]).Execute(); From e93440979ab34c80842de580173fdb70d60bae75 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 17 Jun 2013 02:12:22 +0200 Subject: [PATCH 0328/1224] Re-added tests that got lost in merge. --- .../ExecuteScriptCommandTests.cs | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index ccff00d7..90adda45 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,6 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; +using Common.Logging; + using Moq; using Ploeh.AutoFixture.Xunit; @@ -10,6 +13,10 @@ using System.Linq; +using ScriptCs.Package; + +using Should; + using Xunit.Extensions; namespace ScriptCs.Tests @@ -66,6 +73,62 @@ public void NonManagedAssembliesAreExcluded( executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); executor.Verify(i => i.Terminate(), Times.Once()); } + + [Theory, ScriptCsAutoData] + public void ShouldReturnErrorIfThereIsCompileException( + [Frozen] Mock fileSystem, + [Frozen] Mock executor, + [Frozen] Mock logger, + CommandFactory factory) + { + // Arrange + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + + executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) + .Returns(new ScriptResult { CompileException = new Exception("test") }); + + // Act + var result = factory.CreateCommand(args, new string[0]).Execute(); + + // Assert + result.ShouldEqual(CommandResult.Error); + logger.Verify(i => i.Error(It.IsAny()), Times.Once()); + } + + [Theory, ScriptCsAutoData] + public void ShouldReturnErrorIfThereIsExecuteException( + [Frozen] Mock fileSystem, + [Frozen] Mock executor, + [Frozen] Mock logger, + CommandFactory factory) + { + // Arrange + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + + executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) + .Returns(new ScriptResult { ExecuteException = new Exception("test") }); + + // Act + var result = factory.CreateCommand(args, new string[0]).Execute(); + + // Assert + result.ShouldEqual(CommandResult.Error); + logger.Verify(i => i.Error(It.IsAny()), Times.Once()); + } } } } From ff9f3afb8dfeba3ada63ab55d8e5f36896ee216a Mon Sep 17 00:00:00 2001 From: Adam Ralph Date: Tue, 18 Jun 2013 18:47:29 +0200 Subject: [PATCH 0329/1224] added missing guard clauses upgraded to latest version of LiteGuard.Source --- src/ScriptCs.Core/FilePreProcessor.cs | 11 +++++++++++ src/ScriptCs.Core/FileSystem.cs | 2 ++ src/ScriptCs.Core/Guard.cs | 17 ++++++++++++++++- src/ScriptCs/ScriptCsArgs.cs | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 719937cb..25013d4f 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -33,6 +33,8 @@ public virtual FilePreProcessorResult ProcessScript(string script) protected virtual FilePreProcessorResult Parse(Action parseAction) { + Guard.AgainstNullArgument("parseAction", parseAction); + var context = new FilePreProcessorContext(); _logger.DebugFormat("Starting pre-processing"); @@ -54,6 +56,8 @@ protected virtual FilePreProcessorResult Parse(Action p protected virtual string GenerateCode(FilePreProcessorContext context) { + Guard.AgainstNullArgument("context", context); + var stringBuilder = new StringBuilder(); var usingLines = context.UsingStatements @@ -82,6 +86,9 @@ protected virtual void ParseFile(string path, FilePreProcessorContext context) protected virtual void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) { + Guard.AgainstNullArgument("scriptLines", scriptLines); + Guard.AgainstNullArgument("context", context); + // Insert line directive if there's a path if (path != null) InsertLineDirective(path, scriptLines); @@ -97,6 +104,8 @@ protected virtual void ParseScript(List scriptLines, FilePreProcessorCon protected virtual void InsertLineDirective(string path, List fileLines) { + Guard.AgainstNullArgument("fileLines", fileLines); + var bodyIndex = fileLines.FindIndex(line => PreProcessorUtil.IsNonDirectiveLine(line) && !PreProcessorUtil.IsUsingLine(line)); if (bodyIndex == -1) return; @@ -106,6 +115,8 @@ protected virtual void InsertLineDirective(string path, List fileLines) protected virtual void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) { + Guard.AgainstNullArgument("context", context); + if (PreProcessorUtil.IsUsingLine(line)) { var @using = PreProcessorUtil.GetPath(PreProcessorUtil.UsingString, line); diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 374d66ce..41e9c6c3 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -78,6 +78,8 @@ public void FileDelete(string path) public IEnumerable SplitLines(string value) { + Guard.AgainstNullArgument("value", value); + return value.Split(new[] { NewLine }, StringSplitOptions.None); } diff --git a/src/ScriptCs.Core/Guard.cs b/src/ScriptCs.Core/Guard.cs index c4076255..a5cbf173 100644 --- a/src/ScriptCs.Core/Guard.cs +++ b/src/ScriptCs.Core/Guard.cs @@ -2,6 +2,7 @@ namespace ScriptCs { using System; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; using System.Globalization; /// @@ -17,6 +18,7 @@ internal static class Guard /// The argument. /// is null. /// is restricted to reference types to avoid boxing of value type objects. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] [DebuggerStepThrough] public static void AgainstNullArgument(string parameterName, [ValidatedNotNull]TArgument argument) where TArgument : class { @@ -36,6 +38,7 @@ public static void AgainstNullArgument(string parameterName, [Validat /// /// Performs a type check to avoid boxing of value type objects. /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] [DebuggerStepThrough] public static void AgainstNullArgumentIfNullable(string parameterName, [ValidatedNotNull]TArgument argument) { @@ -54,6 +57,7 @@ public static void AgainstNullArgumentIfNullable(string parameterName /// The argument property. /// is null. /// is restricted to reference types to avoid boxing of value type objects. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] [DebuggerStepThrough] public static void AgainstNullArgumentProperty(string parameterName, string propertyName, [ValidatedNotNull]TProperty argumentProperty) where TProperty : class @@ -75,6 +79,7 @@ public static void AgainstNullArgumentProperty(string parameterName, /// /// Performs a type check to avoid boxing of value type objects. /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] [DebuggerStepThrough] public static void AgainstNullArgumentPropertyIfNullable( string parameterName, string propertyName, [ValidatedNotNull]TProperty argumentProperty) @@ -85,12 +90,22 @@ public static void AgainstNullArgumentPropertyIfNullable( } } + /// + /// Determines whether the specified type is a nullable type. + /// + /// The type. + /// + /// true if the specified type is a nullable type; otherwise, false. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] private static bool IsNullableType(this Type type) { return !type.IsValueType || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); } - // NOTE: when applied to a parameter, this attribute provides an indication to code analysis that the argument has been null checked + /// + /// When applied to a parameter, this attribute provides an indication to code analysis that the argument has been null checked. + /// private sealed class ValidatedNotNullAttribute : Attribute { } diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 0b75acee..a8009099 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -52,6 +52,8 @@ public class ScriptCsArgs public static void SplitScriptArgs(ref string[] args, out string[] scriptArgs) { + Guard.AgainstNullArgument("args", args); + // Split the arguments list on "--". // The arguments before the "--" (or all arguments if there is no "--") are // for ScriptCs.exe, and the arguments after that are for the csx script. From 3ac569deb962140576a20e43765191a06028ccec Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 24 Jun 2013 23:58:25 -0700 Subject: [PATCH 0330/1224] Adding ability to override any service, removing manually creating services by using a temp container --- src/ScriptCs/CompositionRoot.cs | 95 +++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 19862bd7..c4004713 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -18,68 +18,95 @@ public class CompositionRoot { private readonly bool _debug; private readonly LogLevel _logLevel; - private readonly bool _shouldInitDrirectoryCatalog; + private readonly bool _shouldInitDirectoryCatalog; private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; + private IDictionary _overrides; - public CompositionRoot(ScriptCsArgs args) + public CompositionRoot(ScriptCsArgs args) : this(args, new Dictionary()) { - Guard.AgainstNullArgument("args", args); + } + public CompositionRoot(ScriptCsArgs args, IDictionary overrides) + { + Guard.AgainstNullArgument("args", args); + _overrides = overrides; + _debug = args.Debug; _logLevel = args.LogLevel; - _shouldInitDrirectoryCatalog = ShouldInitDrirectoryCatalog(args); + _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(args); } - public void Initialize() + public void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) { + if (_overrides.ContainsKey(typeof (T))) + { + var reg = _overrides[typeof(T)]; + if (reg.GetType().IsSubclassOf(typeof (Type))) + { + builder.RegisterType((Type) reg).As(); + } + else + { + builder.RegisterInstance(reg).As(); + } + } + else + { + registrationAction(builder); + } + } + + public void Initialize() + { var builder = new ContainerBuilder(); builder.RegisterType().As().Exported(x => x.As()); var loggerConfigurator = new LoggerConfigurator(_logLevel); loggerConfigurator.Configure(new ReplConsole()); var logger = loggerConfigurator.GetLogger(); - + builder.RegisterInstance(logger).Exported(x => x.As()); - var types = new[] - { - typeof (ScriptHostFactory), - typeof (FilePreProcessor), - typeof (ScriptPackResolver), - typeof (NugetInstallationProvider), - typeof (PackageInstaller), - }; - - builder.RegisterTypes(types).AsImplementedInterfaces(); - + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + if (_debug) { - builder.RegisterType().As(); - builder.RegisterType().As(); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); } else { - builder.RegisterType().As(); - builder.RegisterType().As(); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); } - builder.RegisterType().As(); + RegisterOverrideOrDefault(builder, b => b.RegisterType()); + + // Hack using a second container to resolve assemblies for MEF catalog before building Autofac container + var tempBuilder = new ContainerBuilder(); + + tempBuilder.RegisterInstance(logger); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - // Hack to resolve assemblies for MEF catalog before building Autofac container - var fileSystem = new FileSystem(); - var assemblyUtility = new AssemblyUtility(); - var packageContainer = new PackageContainer(fileSystem); - var packageAssemblyResolver = new PackageAssemblyResolver(fileSystem, packageContainer); - var assemblyResolver = new AssemblyResolver(fileSystem, packageAssemblyResolver, assemblyUtility, logger); + var tempContainer = tempBuilder.Build(); + var assemblyResolver = tempContainer.Resolve(); - builder.RegisterInstance(fileSystem).As(); - builder.RegisterInstance(assemblyUtility).As(); - builder.RegisterInstance(packageContainer).As(); - builder.RegisterInstance(packageAssemblyResolver).As(); + builder.RegisterInstance(tempContainer.Resolve()).As(); + builder.RegisterInstance(tempContainer.Resolve()).As(); + builder.RegisterInstance(tempContainer.Resolve()).As(); + builder.RegisterInstance(tempContainer.Resolve()).As(); builder.RegisterInstance(assemblyResolver).As(); - if (_shouldInitDrirectoryCatalog) + if (_shouldInitDirectoryCatalog) { var currentDirectory = Environment.CurrentDirectory; var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); @@ -107,7 +134,7 @@ public ILog GetLogger() return _container.Resolve(); } - private static bool ShouldInitDrirectoryCatalog(ScriptCsArgs args) + private static bool ShouldInitDirectoryCatalog(ScriptCsArgs args) { return args.Repl || !string.IsNullOrWhiteSpace(args.ScriptName); } From bb694a662fcd11311f16394afac4150c395a73b4 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 00:51:26 -0700 Subject: [PATCH 0331/1224] Extracting engine and executor to be passed in so CR can be moved to core --- src/ScriptCs/CompositionRoot.cs | 39 +++++++++++++++++++-------------- src/ScriptCs/Program.cs | 17 +++++++++++++- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index c4004713..26b481a9 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -16,23 +16,38 @@ namespace ScriptCs { public class CompositionRoot { - private readonly bool _debug; private readonly LogLevel _logLevel; private readonly bool _shouldInitDirectoryCatalog; private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; private IDictionary _overrides; + private Type _scriptExecutorType; + private Type _scriptEngineType; - public CompositionRoot(ScriptCsArgs args) : this(args, new Dictionary()) + public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEngineType) : this(args, scriptExecutorType, scriptEngineType, new Dictionary()) { } - public CompositionRoot(ScriptCsArgs args, IDictionary overrides) + public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) { Guard.AgainstNullArgument("args", args); + Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); + Guard.AgainstNullArgument("scriptEngine", scriptEngineType); + + if (!typeof(IScriptExecutor).IsAssignableFrom(scriptExecutorType)) + { + throw new ArgumentException("scriptExecutor type must implement IScriptExecutor", "scriptExecutor"); + } + + if (!typeof (IScriptEngine).IsAssignableFrom(scriptEngineType)) + { + throw new ArgumentException("scriptEgnine type must implement IScriptEngine", "scriptEngine"); + } + + _scriptExecutorType = scriptExecutorType; + _scriptEngineType = scriptEngineType; + _overrides = overrides; - - _debug = args.Debug; _logLevel = args.LogLevel; _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(args); } @@ -67,24 +82,14 @@ public void Initialize() var logger = loggerConfigurator.GetLogger(); builder.RegisterInstance(logger).Exported(x => x.As()); + builder.RegisterType(_scriptEngineType).As(); + builder.RegisterType(_scriptExecutorType).As(); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - - if (_debug) - { - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - } - else - { - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - } - RegisterOverrideOrDefault(builder, b => b.RegisterType()); // Hack using a second container to resolve assemblies for MEF catalog before building Autofac container diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index cdced5ae..ca6b339a 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -3,6 +3,7 @@ using PowerArgs; using ScriptCs.Command; using System.Linq; +using ScriptCs.Engine.Roslyn; namespace ScriptCs { @@ -12,10 +13,24 @@ private static int Main(string[] args) { string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + Type scriptExecutorType; + Type scriptEngineType; var commandArgs = ParseArguments(args); + - var compositionRoot = new CompositionRoot(commandArgs); + if (commandArgs.Debug) + { + scriptExecutorType = typeof (DebugScriptExecutor); + scriptEngineType = typeof (RoslynScriptDebuggerEngine); + } + else + { + scriptExecutorType = typeof (ScriptExecutor); + scriptEngineType = typeof (RoslynScriptEngine); + } + + var compositionRoot = new CompositionRoot(commandArgs, scriptExecutorType, scriptEngineType); compositionRoot.Initialize(); var logger = compositionRoot.GetLogger(); From 83ee88cf565eb63d4195f6b18545e87128fa420c Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 00:53:44 -0700 Subject: [PATCH 0332/1224] fixing typo --- src/ScriptCs/CompositionRoot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 26b481a9..e7b706ba 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -41,7 +41,7 @@ public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEn if (!typeof (IScriptEngine).IsAssignableFrom(scriptEngineType)) { - throw new ArgumentException("scriptEgnine type must implement IScriptEngine", "scriptEngine"); + throw new ArgumentException("scriptEngine type must implement IScriptEngine", "scriptEngine"); } _scriptExecutorType = scriptExecutorType; From f76c6e22dd4437bd23443302b2133108bb2a8500 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 02:00:40 -0700 Subject: [PATCH 0333/1224] Moving CompositionRoot to core, renaming ReplConsole to IConsole and doing a bunch of necessary refactorings to cut the CR dependencies --- ScriptCs.sln.ide/graph/ScriptCs.sln.ide | 3 + scriptcs_debug.sln | 37 ++++++++++++ .../CompositionRoot.cs | 58 +++++++++++-------- src/ScriptCs.Core/ILoggerConfigurator.cs | 13 +++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 6 ++ .../ScriptServiceRoot.cs | 0 src/ScriptCs.Core/packages.config | 1 + src/ScriptCs/LoggerConfigurator.cs | 2 +- src/ScriptCs/Program.cs | 7 ++- .../{ReplConsole.cs => ScriptConsole.cs} | 4 +- src/ScriptCs/ScriptCs.csproj | 6 +- 11 files changed, 102 insertions(+), 35 deletions(-) create mode 100644 ScriptCs.sln.ide/graph/ScriptCs.sln.ide create mode 100644 scriptcs_debug.sln rename src/{ScriptCs => ScriptCs.Core}/CompositionRoot.cs (74%) create mode 100644 src/ScriptCs.Core/ILoggerConfigurator.cs rename src/{ScriptCs => ScriptCs.Core}/ScriptServiceRoot.cs (100%) rename src/ScriptCs/{ReplConsole.cs => ScriptConsole.cs} (93%) diff --git a/ScriptCs.sln.ide/graph/ScriptCs.sln.ide b/ScriptCs.sln.ide/graph/ScriptCs.sln.ide new file mode 100644 index 00000000..4b1badd9 --- /dev/null +++ b/ScriptCs.sln.ide/graph/ScriptCs.sln.ide @@ -0,0 +1,3 @@ + + 0001-01-01T00:00:00Z + \ No newline at end of file diff --git a/scriptcs_debug.sln b/scriptcs_debug.sln new file mode 100644 index 00000000..24e9cece --- /dev/null +++ b/scriptcs_debug.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "scriptcs", "src\ScriptCs\bin\Debug\scriptcs.exe", "{D797ABD7-8971-4227-B9C4-8ECC158FD12B}" + ProjectSection(DebuggerProjectSystem) = preProject + PortSupplier = 00000000-0000-0000-0000-000000000000 + Executable = C:\code\scriptcs\src\ScriptCs\bin\Debug\scriptcs.exe + RemoteMachine = GBLOCK-WIN8 + StartingDirectory = C:\code\scriptcs-samples\wpf + Arguments = start.csx -debug + Environment = Default + LaunchingEngine = 00000000-0000-0000-0000-000000000000 + LaunchSQLEngine = No + AttachLaunchAction = No + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39CDE834-543F-4352-AF43-F1CA3D6CCBFF}" + ProjectSection(SolutionItems) = preProject + ..\scriptcs-samples\wpf\CalculatorView.xaml = ..\scriptcs-samples\wpf\CalculatorView.xaml + ..\scriptcs-samples\wpf\mvvm.csx = ..\scriptcs-samples\wpf\mvvm.csx + ..\scriptcs-samples\wpf\start.csx = ..\scriptcs-samples\wpf\start.csx + ..\scriptcs-samples\wpf\utilities.csx = ..\scriptcs-samples\wpf\utilities.csx + ..\scriptcs-samples\wpf\viewmodels.csx = ..\scriptcs-samples\wpf\viewmodels.csx + ..\scriptcs-samples\wpf\views.csx = ..\scriptcs-samples\wpf\views.csx + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D797ABD7-8971-4227-B9C4-8ECC158FD12B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs.Core/CompositionRoot.cs similarity index 74% rename from src/ScriptCs/CompositionRoot.cs rename to src/ScriptCs.Core/CompositionRoot.cs index e7b706ba..eaf14efe 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs.Core/CompositionRoot.cs @@ -8,7 +8,6 @@ using Autofac.Integration.Mef; using Common.Logging; using ScriptCs.Contracts; -using ScriptCs.Engine.Roslyn; using ScriptCs.Package; using ScriptCs.Package.InstallationProvider; @@ -16,50 +15,59 @@ namespace ScriptCs { public class CompositionRoot { - private readonly LogLevel _logLevel; private readonly bool _shouldInitDirectoryCatalog; private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; private IDictionary _overrides; private Type _scriptExecutorType; private Type _scriptEngineType; + private IConsole _console; + private string _scriptName; + private bool _repl; + private ILoggerConfigurator _loggerConfigurator; - public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEngineType) : this(args, scriptExecutorType, scriptEngineType, new Dictionary()) + public CompositionRoot(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType) + : this(scriptName, repl, loggerConfigurator, console, scriptExecutorType, scriptEngineType, new Dictionary()) { } - public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) + public CompositionRoot(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) { - Guard.AgainstNullArgument("args", args); Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); Guard.AgainstNullArgument("scriptEngine", scriptEngineType); + Guard.AgainstNullArgument("console", console); + Guard.AgainstNullArgument("loggerConfigurator", loggerConfigurator); + + _loggerConfigurator = loggerConfigurator; + _console = console; + _scriptName = scriptName; + _repl = repl; if (!typeof(IScriptExecutor).IsAssignableFrom(scriptExecutorType)) { throw new ArgumentException("scriptExecutor type must implement IScriptExecutor", "scriptExecutor"); } - - if (!typeof (IScriptEngine).IsAssignableFrom(scriptEngineType)) + + if (!typeof(IScriptEngine).IsAssignableFrom(scriptEngineType)) { throw new ArgumentException("scriptEngine type must implement IScriptEngine", "scriptEngine"); } _scriptExecutorType = scriptExecutorType; _scriptEngineType = scriptEngineType; - + _overrides = overrides; - _logLevel = args.LogLevel; - _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(args); + _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(_repl, _scriptName); } public void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) { - if (_overrides.ContainsKey(typeof (T))) + if (_overrides.ContainsKey(typeof(T))) { var reg = _overrides[typeof(T)]; - if (reg.GetType().IsSubclassOf(typeof (Type))) + if (reg.GetType().IsSubclassOf(typeof(Type))) { - builder.RegisterType((Type) reg).As(); + builder.RegisterType((Type)reg).As(); } else { @@ -73,17 +81,16 @@ public void RegisterOverrideOrDefault(ContainerBuilder builder, Action().As().Exported(x => x.As()); + + _loggerConfigurator.Configure(_console); + var logger = _loggerConfigurator.GetLogger(); - var loggerConfigurator = new LoggerConfigurator(_logLevel); - loggerConfigurator.Configure(new ReplConsole()); - var logger = loggerConfigurator.GetLogger(); - builder.RegisterInstance(logger).Exported(x => x.As()); builder.RegisterType(_scriptEngineType).As(); builder.RegisterType(_scriptExecutorType).As(); + builder.RegisterInstance(_console).As(); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); @@ -97,9 +104,9 @@ public void Initialize() tempBuilder.RegisterInstance(logger); RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); var tempContainer = tempBuilder.Build(); @@ -126,7 +133,7 @@ public void Initialize() _container = builder.Build(); - _scriptServiceRoot = _container.Resolve(); + _scriptServiceRoot = _container.Resolve(); } public ScriptServiceRoot GetServiceRoot() @@ -139,9 +146,10 @@ public ILog GetLogger() return _container.Resolve(); } - private static bool ShouldInitDirectoryCatalog(ScriptCsArgs args) + private static bool ShouldInitDirectoryCatalog(bool repl, string scriptName) { - return args.Repl || !string.IsNullOrWhiteSpace(args.ScriptName); + return repl || !string.IsNullOrWhiteSpace(scriptName); } } } + diff --git a/src/ScriptCs.Core/ILoggerConfigurator.cs b/src/ScriptCs.Core/ILoggerConfigurator.cs new file mode 100644 index 00000000..4494037e --- /dev/null +++ b/src/ScriptCs.Core/ILoggerConfigurator.cs @@ -0,0 +1,13 @@ +using Common.Logging; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public interface ILoggerConfigurator + { + void Configure(IConsole console); + ILog GetLogger(); + } +} + + diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 9c78920e..6a5e3db1 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -29,6 +29,9 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + + ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll + ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll @@ -44,6 +47,7 @@ + @@ -61,6 +65,7 @@ + @@ -89,6 +94,7 @@ + diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs.Core/ScriptServiceRoot.cs similarity index 100% rename from src/ScriptCs/ScriptServiceRoot.cs rename to src/ScriptCs.Core/ScriptServiceRoot.cs diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 0d6dfbdf..761319e9 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -4,5 +4,6 @@ + \ No newline at end of file diff --git a/src/ScriptCs/LoggerConfigurator.cs b/src/ScriptCs/LoggerConfigurator.cs index bb2597a0..2b4e6d92 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/src/ScriptCs/LoggerConfigurator.cs @@ -10,7 +10,7 @@ namespace ScriptCs { - public class LoggerConfigurator + public class LoggerConfigurator : ILoggerConfigurator { private const string ThreadPattern = " Thread[%thread]"; private const string Pattern = "%-5level{threadLevel}: %message%newline"; diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index ca6b339a..76b2ccb3 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -17,8 +17,7 @@ private static int Main(string[] args) Type scriptEngineType; var commandArgs = ParseArguments(args); - - + if (commandArgs.Debug) { scriptExecutorType = typeof (DebugScriptExecutor); @@ -30,7 +29,9 @@ private static int Main(string[] args) scriptEngineType = typeof (RoslynScriptEngine); } - var compositionRoot = new CompositionRoot(commandArgs, scriptExecutorType, scriptEngineType); + var loggerConfigurator = new LoggerConfigurator(commandArgs.LogLevel); + + var compositionRoot = new CompositionRoot(commandArgs.ScriptName, commandArgs.Repl,loggerConfigurator,new ScriptConsole(), scriptExecutorType, scriptEngineType); compositionRoot.Initialize(); var logger = compositionRoot.GetLogger(); diff --git a/src/ScriptCs/ReplConsole.cs b/src/ScriptCs/ScriptConsole.cs similarity index 93% rename from src/ScriptCs/ReplConsole.cs rename to src/ScriptCs/ScriptConsole.cs index 1df082ef..2a40f14a 100644 --- a/src/ScriptCs/ReplConsole.cs +++ b/src/ScriptCs/ScriptConsole.cs @@ -3,9 +3,9 @@ namespace ScriptCs { - public class ReplConsole : IConsole + public class ScriptConsole : IConsole { - public ReplConsole() + public ScriptConsole() { Console.CancelKeyPress += HandleCancelKeyPress; } diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 8a4d8b25..fcdb9c82 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -73,15 +73,13 @@ - - + + - - From 7a8f3e17c8def7880cd9e725ce6d86c6f9e63d83 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 02:13:38 -0700 Subject: [PATCH 0334/1224] removing PowerArgs from core --- src/ScriptCs.Core/ScriptCs.Core.csproj | 3 --- src/ScriptCs.Core/packages.config | 1 - 2 files changed, 4 deletions(-) diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 6a5e3db1..0a54e099 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -29,9 +29,6 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll - - ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll - ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 761319e9..0d6dfbdf 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -4,6 +4,5 @@ - \ No newline at end of file From dcfdfe4bdff98e6ba2a214bc29d98e23038cd205 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 03:38:18 -0700 Subject: [PATCH 0335/1224] Adding unit tests --- src/ScriptCs.Core/CompositionRoot.cs | 4 +- .../CompositionRootTests.cs | 318 ++++++++++++++++++ .../ScriptCs.Core.Tests.csproj | 8 + test/ScriptCs.Core.Tests/packages.config | 1 + 4 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 test/ScriptCs.Core.Tests/CompositionRootTests.cs diff --git a/src/ScriptCs.Core/CompositionRoot.cs b/src/ScriptCs.Core/CompositionRoot.cs index eaf14efe..0687a62f 100644 --- a/src/ScriptCs.Core/CompositionRoot.cs +++ b/src/ScriptCs.Core/CompositionRoot.cs @@ -80,7 +80,7 @@ public void RegisterOverrideOrDefault(ContainerBuilder builder, Action(); builder.RegisterType(_scriptExecutorType).As(); builder.RegisterInstance(_console).As(); + builder.RegisterType(); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); @@ -134,6 +135,7 @@ public void Initialize() _container = builder.Build(); _scriptServiceRoot = _container.Resolve(); + return _container; } public ScriptServiceRoot GetServiceRoot() diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/CompositionRootTests.cs new file mode 100644 index 00000000..d77829fd --- /dev/null +++ b/test/ScriptCs.Core.Tests/CompositionRootTests.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Common.Logging; +using Moq; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; +using Xunit; +using Should; + +namespace ScriptCs.Tests +{ + public class CompositionRootTests + { + public class TheInitializeMethod + { + private Mock _mockConsole = new Mock(); + private Type _scriptExecutorType = null; + private Type _scriptEngineType = null; + private Mock _mockLoggerConfigurator = new Mock(); + private Mock _mockLogger = new Mock(); + private IDictionary _overrides = new Dictionary(); + + public TheInitializeMethod() + { + var mockScriptExecutorType = new Mock(); + _scriptExecutorType = mockScriptExecutorType.Object.GetType(); + + var mockScriptEngineType = new Mock(); + _scriptEngineType = mockScriptEngineType.Object.GetType(); + + _mockLoggerConfigurator.Setup(l => l.GetLogger()).Returns(_mockLogger.Object); + } + + [Fact] + public void ShouldInvokeTheConfigureMethod() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + root.Initialize(); + _mockLoggerConfigurator.Verify(l=>l.Configure(It.IsAny())); + + } + + [Fact] + public void ShouldGetTheLogger() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + root.Initialize(); + _mockLoggerConfigurator.Verify(l=>l.GetLogger()); + } + + [Fact] + public void ShouldRegisterTheLoggerInstance() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + var logger = container.Resolve(); + logger.ShouldEqual(_mockLogger.Object); + } + + [Fact] + public void ShouldRegisterTheScriptEngine() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + var engine = container.Resolve(); + engine.GetType().ShouldEqual(_scriptEngineType); + } + + [Fact] + public void ShouldRegisterTheExecutor() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + var executor = container.Resolve(); + executor.GetType().ShouldEqual(_scriptExecutorType); + } + + [Fact] + public void ShouldRegisterTheConsoleInstance() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheServiceRoot() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + + [Fact] + public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultFileSystemIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldReturnTheLoggerWhenGetLoggerIsInvoked() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + root.Initialize(); + root.GetLogger().ShouldEqual(_mockLogger.Object); + } + + [Fact] + public void ShouldReturnTheScriptServiceRootWhenTheGetterIsInvoked() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + root.Initialize(); + root.GetServiceRoot().ShouldNotBeNull(); + + } + + [Fact] + public void ShouldRegisterTheOverriddenScriptHostFactory() + { + var mock = new Mock(); + _overrides[typeof (IScriptHostFactory)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenFilePreProcessor() + { + var mock = new Mock(); + _overrides[typeof(IFilePreProcessor)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenScriptPackResolver() + { + var mock = new Mock(); + _overrides[typeof(IScriptPackResolver)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenInstallationProvider() + { + var mock = new Mock(); + _overrides[typeof(IInstallationProvider)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageInstaller() + { + var mock = new Mock(); + _overrides[typeof(IPackageInstaller)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + public class TestFileSystem : FileSystem + { + } + + [Fact] + public void ShouldRegisterTheOverriddenFileSystem() + { + _overrides[typeof(IFileSystem)] = new TestFileSystem(); + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(); + } + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyUtility() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyUtility)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageContainer() + { + var mock = new Mock(); + _overrides[typeof(IPackageContainer)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageAssemblyResolver() + { + var mock = new Mock(); + _overrides[typeof(IPackageAssemblyResolver)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyResolver() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyResolver)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + + + } + } +} diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index b2d1e374..f11fec92 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -9,6 +9,13 @@ ..\..\ + + False + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.Configuration.dll + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll @@ -38,6 +45,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Core.Tests/packages.config b/test/ScriptCs.Core.Tests/packages.config index ae265215..2fc851e7 100644 --- a/test/ScriptCs.Core.Tests/packages.config +++ b/test/ScriptCs.Core.Tests/packages.config @@ -1,5 +1,6 @@  + From dcd8156eed1b33884d40afcafb3ed75fd4de2b7e Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 03:40:17 -0700 Subject: [PATCH 0336/1224] removing whitespace --- test/ScriptCs.Core.Tests/CompositionRootTests.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/CompositionRootTests.cs index d77829fd..1b3c97eb 100644 --- a/test/ScriptCs.Core.Tests/CompositionRootTests.cs +++ b/test/ScriptCs.Core.Tests/CompositionRootTests.cs @@ -251,7 +251,6 @@ public void ShouldRegisterTheOverriddenPackageInstaller() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } public class TestFileSystem : FileSystem @@ -275,7 +274,6 @@ public void ShouldRegisterTheOverriddenAssemblyUtility() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } [Fact] @@ -286,7 +284,6 @@ public void ShouldRegisterTheOverriddenPackageContainer() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } [Fact] @@ -297,7 +294,6 @@ public void ShouldRegisterTheOverriddenPackageAssemblyResolver() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } [Fact] @@ -308,7 +304,6 @@ public void ShouldRegisterTheOverriddenAssemblyResolver() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } From ece779d6e90ee66057a817de1195e4f3213a3df9 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 03:44:30 -0700 Subject: [PATCH 0337/1224] fixing tests to register by type --- .../CompositionRootTests.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/CompositionRootTests.cs index 1b3c97eb..154a11fc 100644 --- a/test/ScriptCs.Core.Tests/CompositionRootTests.cs +++ b/test/ScriptCs.Core.Tests/CompositionRootTests.cs @@ -206,7 +206,7 @@ public void ShouldReturnTheScriptServiceRootWhenTheGetterIsInvoked() public void ShouldRegisterTheOverriddenScriptHostFactory() { var mock = new Mock(); - _overrides[typeof (IScriptHostFactory)] = mock.Object; + _overrides[typeof (IScriptHostFactory)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -216,7 +216,7 @@ public void ShouldRegisterTheOverriddenScriptHostFactory() public void ShouldRegisterTheOverriddenFilePreProcessor() { var mock = new Mock(); - _overrides[typeof(IFilePreProcessor)] = mock.Object; + _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -227,7 +227,7 @@ public void ShouldRegisterTheOverriddenFilePreProcessor() public void ShouldRegisterTheOverriddenScriptPackResolver() { var mock = new Mock(); - _overrides[typeof(IScriptPackResolver)] = mock.Object; + _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -237,7 +237,7 @@ public void ShouldRegisterTheOverriddenScriptPackResolver() public void ShouldRegisterTheOverriddenInstallationProvider() { var mock = new Mock(); - _overrides[typeof(IInstallationProvider)] = mock.Object; + _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -247,7 +247,7 @@ public void ShouldRegisterTheOverriddenInstallationProvider() public void ShouldRegisterTheOverriddenPackageInstaller() { var mock = new Mock(); - _overrides[typeof(IPackageInstaller)] = mock.Object; + _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -260,7 +260,7 @@ public class TestFileSystem : FileSystem [Fact] public void ShouldRegisterTheOverriddenFileSystem() { - _overrides[typeof(IFileSystem)] = new TestFileSystem(); + _overrides[typeof(IFileSystem)] = typeof(TestFileSystem); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(); @@ -270,7 +270,7 @@ public void ShouldRegisterTheOverriddenFileSystem() public void ShouldRegisterTheOverriddenAssemblyUtility() { var mock = new Mock(); - _overrides[typeof(IAssemblyUtility)] = mock.Object; + _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -280,7 +280,7 @@ public void ShouldRegisterTheOverriddenAssemblyUtility() public void ShouldRegisterTheOverriddenPackageContainer() { var mock = new Mock(); - _overrides[typeof(IPackageContainer)] = mock.Object; + _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -290,7 +290,7 @@ public void ShouldRegisterTheOverriddenPackageContainer() public void ShouldRegisterTheOverriddenPackageAssemblyResolver() { var mock = new Mock(); - _overrides[typeof(IPackageAssemblyResolver)] = mock.Object; + _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -300,7 +300,7 @@ public void ShouldRegisterTheOverriddenPackageAssemblyResolver() public void ShouldRegisterTheOverriddenAssemblyResolver() { var mock = new Mock(); - _overrides[typeof(IAssemblyResolver)] = mock.Object; + _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); From 7dd8e1d736ccae495d1d59c79a8cae68907f19f2 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 03:50:17 -0700 Subject: [PATCH 0338/1224] Adding an instance override test --- test/ScriptCs.Core.Tests/CompositionRootTests.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/CompositionRootTests.cs index 154a11fc..034236cf 100644 --- a/test/ScriptCs.Core.Tests/CompositionRootTests.cs +++ b/test/ScriptCs.Core.Tests/CompositionRootTests.cs @@ -306,6 +306,17 @@ public void ShouldRegisterTheOverriddenAssemblyResolver() container.Resolve().ShouldBeType(mock.Object.GetType()); } + [Fact] + public void ShouldRegisterTheOverriddenAssemblyResolverInstance() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyResolver)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldEqual(mock.Object); + } + + } From 1d5069846420a36aa4509beb03d46d0acdf9dd45 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 25 Jun 2013 09:28:53 -0700 Subject: [PATCH 0339/1224] Resetting CommonVersionInfo.cs content --- common/CommonVersionInfo.cs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index 270505b9..590a13eb 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,18 +1,9 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18033 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; using System.Reflection; -[assembly: System.Reflection.AssemblyVersionAttribute("0.5.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("0.5.0-alpha")] - -// Generated by the MSBuild WriteCodeFragment class on 16/05/2013 1:24:46 PM. +/** + * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the + * contents of 'build\ScriptCs.Version.props'. + **/ +[assembly: AssemblyVersion("0.0.0")] +[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file From 0098498cc72e86e1473eb6dab548eadd45072231 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 25 Jun 2013 10:57:14 -0600 Subject: [PATCH 0340/1224] Ignore *.bak files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 11b6d0f7..362c5a12 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ x64/ *.tlh *.tmp *.log +*.bak *.vspscc *.vssscc .builds @@ -107,4 +108,4 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML -artifacts \ No newline at end of file +artifacts From aba0d6aa1cd19224789f64c6044b05a4ed133a36 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 14:44:58 -0700 Subject: [PATCH 0341/1224] Renaming CompositionRoot and ServiceRoot, fix for #351 --- src/ScriptCs.Core/ScriptCs.Core.csproj | 4 +- .../{CompositionRoot.cs => ScriptRuntime.cs} | 18 +-- ...ScriptServiceRoot.cs => ScriptServices.cs} | 4 +- src/ScriptCs/Command/CommandFactory.cs | 64 ++++----- src/ScriptCs/Program.cs | 6 +- .../ScriptCs.Core.Tests.csproj | 2 +- ...tionRootTests.cs => ScriptRuntimeTests.cs} | 136 +++++++++--------- test/ScriptCs.Tests/CleanCommandTests.cs | 2 +- test/ScriptCs.Tests/CommandFactoryTests.cs | 4 +- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 2 +- .../ExecuteScriptCommandTests.cs | 8 +- test/ScriptCs.Tests/InstallCommandTests.cs | 4 +- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 13 files changed, 128 insertions(+), 128 deletions(-) rename src/ScriptCs.Core/{CompositionRoot.cs => ScriptRuntime.cs} (88%) rename src/ScriptCs.Core/{ScriptServiceRoot.cs => ScriptServices.cs} (95%) rename test/ScriptCs.Core.Tests/{CompositionRootTests.cs => ScriptRuntimeTests.cs} (56%) diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 0a54e099..361d92e7 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -44,7 +44,7 @@ - + @@ -91,7 +91,7 @@ - + diff --git a/src/ScriptCs.Core/CompositionRoot.cs b/src/ScriptCs.Core/ScriptRuntime.cs similarity index 88% rename from src/ScriptCs.Core/CompositionRoot.cs rename to src/ScriptCs.Core/ScriptRuntime.cs index 0687a62f..6d073ffd 100644 --- a/src/ScriptCs.Core/CompositionRoot.cs +++ b/src/ScriptCs.Core/ScriptRuntime.cs @@ -13,11 +13,11 @@ namespace ScriptCs { - public class CompositionRoot + public class ScriptRuntime { private readonly bool _shouldInitDirectoryCatalog; private IContainer _container; - private ScriptServiceRoot _scriptServiceRoot; + private ScriptServices _scriptServices; private IDictionary _overrides; private Type _scriptExecutorType; private Type _scriptEngineType; @@ -26,12 +26,12 @@ public class CompositionRoot private bool _repl; private ILoggerConfigurator _loggerConfigurator; - public CompositionRoot(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType) + public ScriptRuntime(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType) : this(scriptName, repl, loggerConfigurator, console, scriptExecutorType, scriptEngineType, new Dictionary()) { } - public CompositionRoot(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) + public ScriptRuntime(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) { Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); Guard.AgainstNullArgument("scriptEngine", scriptEngineType); @@ -91,14 +91,14 @@ public IContainer Initialize() builder.RegisterType(_scriptEngineType).As(); builder.RegisterType(_scriptExecutorType).As(); builder.RegisterInstance(_console).As(); - builder.RegisterType(); + builder.RegisterType(); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType()); + RegisterOverrideOrDefault(builder, b => b.RegisterType()); // Hack using a second container to resolve assemblies for MEF catalog before building Autofac container var tempBuilder = new ContainerBuilder(); @@ -134,13 +134,13 @@ public IContainer Initialize() _container = builder.Build(); - _scriptServiceRoot = _container.Resolve(); + _scriptServices = _container.Resolve(); return _container; } - public ScriptServiceRoot GetServiceRoot() + public ScriptServices GetScriptServices() { - return _scriptServiceRoot; + return _scriptServices; } public ILog GetLogger() diff --git a/src/ScriptCs.Core/ScriptServiceRoot.cs b/src/ScriptCs.Core/ScriptServices.cs similarity index 95% rename from src/ScriptCs.Core/ScriptServiceRoot.cs rename to src/ScriptCs.Core/ScriptServices.cs index d8d665bb..a144d45e 100644 --- a/src/ScriptCs.Core/ScriptServiceRoot.cs +++ b/src/ScriptCs.Core/ScriptServices.cs @@ -4,9 +4,9 @@ namespace ScriptCs { - public class ScriptServiceRoot + public class ScriptServices { - public ScriptServiceRoot( + public ScriptServices( IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IScriptExecutor executor, diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index f322affb..fb077817 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -4,11 +4,11 @@ namespace ScriptCs.Command { public class CommandFactory { - private readonly ScriptServiceRoot _scriptServiceRoot; + private readonly ScriptServices _scriptServices; - public CommandFactory(ScriptServiceRoot scriptServiceRoot) + public CommandFactory(ScriptServices scriptServices) { - _scriptServiceRoot = scriptServiceRoot; + _scriptServices = scriptServices; } public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) @@ -17,19 +17,19 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Help) { - return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: true); + return new ShowUsageCommand(_scriptServices.Logger, isValid: true); } if (args.Repl) { var replCommand = new ExecuteReplCommand( - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Engine, - _scriptServiceRoot.FilePreProcessor, - _scriptServiceRoot.Logger, - _scriptServiceRoot.Console, - _scriptServiceRoot.AssemblyResolver); + _scriptServices.FileSystem, + _scriptServices.ScriptPackResolver, + _scriptServices.Engine, + _scriptServices.FilePreProcessor, + _scriptServices.Logger, + _scriptServices.Console, + _scriptServices.AssemblyResolver); return replCommand; } @@ -39,13 +39,13 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) var executeCommand = new ExecuteScriptCommand( args.ScriptName, scriptArgs, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.Executor, - _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Logger, - _scriptServiceRoot.AssemblyResolver); + _scriptServices.FileSystem, + _scriptServices.Executor, + _scriptServices.ScriptPackResolver, + _scriptServices.Logger, + _scriptServices.AssemblyResolver); - var fileSystem = _scriptServiceRoot.FileSystem; + var fileSystem = _scriptServices.FileSystem; var currentDirectory = fileSystem.CurrentDirectory; var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); var packagesFolder = Path.Combine(currentDirectory, Constants.PackagesFolder); @@ -56,9 +56,9 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) null, false, fileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.PackageInstaller, - _scriptServiceRoot.Logger); + _scriptServices.PackageAssemblyResolver, + _scriptServices.PackageInstaller, + _scriptServices.Logger); return new CompositeCommand(installCommand, executeCommand); } @@ -71,17 +71,17 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) var installCommand = new InstallCommand( args.Install, args.AllowPreRelease, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.PackageInstaller, - _scriptServiceRoot.Logger); + _scriptServices.FileSystem, + _scriptServices.PackageAssemblyResolver, + _scriptServices.PackageInstaller, + _scriptServices.Logger); - var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; + var currentDirectory = _scriptServices.FileSystem.CurrentDirectory; var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); - if (!_scriptServiceRoot.FileSystem.FileExists(packageFile)) + if (!_scriptServices.FileSystem.FileExists(packageFile)) { - var saveCommand = new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + var saveCommand = new SaveCommand(_scriptServices.PackageAssemblyResolver); return new CompositeCommand(installCommand, saveCommand); } @@ -90,19 +90,19 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Clean) { - var saveCommand = new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + var saveCommand = new SaveCommand(_scriptServices.PackageAssemblyResolver); var cleanCommand = new CleanCommand( args.ScriptName, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.Logger); + _scriptServices.FileSystem, + _scriptServices.Logger); return new CompositeCommand(saveCommand, cleanCommand); } if (args.Save) { - return new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + return new SaveCommand(_scriptServices.PackageAssemblyResolver); } if (args.Version) @@ -110,7 +110,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) return new VersionCommand(); } - return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: false); + return new ShowUsageCommand(_scriptServices.Logger, isValid: false); } } } diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 76b2ccb3..ca1d0b28 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -31,13 +31,13 @@ private static int Main(string[] args) var loggerConfigurator = new LoggerConfigurator(commandArgs.LogLevel); - var compositionRoot = new CompositionRoot(commandArgs.ScriptName, commandArgs.Repl,loggerConfigurator,new ScriptConsole(), scriptExecutorType, scriptEngineType); + var compositionRoot = new ScriptRuntime(commandArgs.ScriptName, commandArgs.Repl,loggerConfigurator,new ScriptConsole(), scriptExecutorType, scriptEngineType); compositionRoot.Initialize(); var logger = compositionRoot.GetLogger(); - logger.Debug("Creating ScriptServiceRoot"); + logger.Debug("Creating ScriptServices"); - var scriptServiceRoot = compositionRoot.GetServiceRoot(); + var scriptServiceRoot = compositionRoot.GetScriptServices(); var commandFactory = new CommandFactory(scriptServiceRoot); var command = commandFactory.CreateCommand(commandArgs, scriptArgs); diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index f11fec92..4052b23c 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -45,7 +45,7 @@ Properties\CommonVersionInfo.cs - + diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs similarity index 56% rename from test/ScriptCs.Core.Tests/CompositionRootTests.cs rename to test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs index 034236cf..61c20a5b 100644 --- a/test/ScriptCs.Core.Tests/CompositionRootTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs @@ -14,7 +14,7 @@ namespace ScriptCs.Tests { - public class CompositionRootTests + public class ScriptRuntimeTests { public class TheInitializeMethod { @@ -39,8 +39,8 @@ public TheInitializeMethod() [Fact] public void ShouldInvokeTheConfigureMethod() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + runtime.Initialize(); _mockLoggerConfigurator.Verify(l=>l.Configure(It.IsAny())); } @@ -48,16 +48,16 @@ public void ShouldInvokeTheConfigureMethod() [Fact] public void ShouldGetTheLogger() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + runtime.Initialize(); _mockLoggerConfigurator.Verify(l=>l.GetLogger()); } [Fact] public void ShouldRegisterTheLoggerInstance() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); var logger = container.Resolve(); logger.ShouldEqual(_mockLogger.Object); } @@ -65,8 +65,8 @@ public void ShouldRegisterTheLoggerInstance() [Fact] public void ShouldRegisterTheScriptEngine() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); var engine = container.Resolve(); engine.GetType().ShouldEqual(_scriptEngineType); } @@ -74,8 +74,8 @@ public void ShouldRegisterTheScriptEngine() [Fact] public void ShouldRegisterTheExecutor() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); var executor = container.Resolve(); executor.GetType().ShouldEqual(_scriptExecutorType); } @@ -83,122 +83,122 @@ public void ShouldRegisterTheExecutor() [Fact] public void ShouldRegisterTheConsoleInstance() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] - public void ShouldRegisterTheServiceRoot() + public void ShouldRegisterTheScriptServices() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); - container.Resolve().ShouldNotBeNull(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); + container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); - container.Resolve().ShouldNotBeNull(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); + container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultFileSystemIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldReturnTheLoggerWhenGetLoggerIsInvoked() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - root.Initialize(); - root.GetLogger().ShouldEqual(_mockLogger.Object); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + runtime.Initialize(); + runtime.GetLogger().ShouldEqual(_mockLogger.Object); } [Fact] public void ShouldReturnTheScriptServiceRootWhenTheGetterIsInvoked() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - root.Initialize(); - root.GetServiceRoot().ShouldNotBeNull(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + runtime.Initialize(); + runtime.GetScriptServices().ShouldNotBeNull(); } @@ -207,8 +207,8 @@ public void ShouldRegisterTheOverriddenScriptHostFactory() { var mock = new Mock(); _overrides[typeof (IScriptHostFactory)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -217,8 +217,8 @@ public void ShouldRegisterTheOverriddenFilePreProcessor() { var mock = new Mock(); _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -228,8 +228,8 @@ public void ShouldRegisterTheOverriddenScriptPackResolver() { var mock = new Mock(); _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -238,8 +238,8 @@ public void ShouldRegisterTheOverriddenInstallationProvider() { var mock = new Mock(); _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -248,8 +248,8 @@ public void ShouldRegisterTheOverriddenPackageInstaller() { var mock = new Mock(); _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -261,8 +261,8 @@ public class TestFileSystem : FileSystem public void ShouldRegisterTheOverriddenFileSystem() { _overrides[typeof(IFileSystem)] = typeof(TestFileSystem); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(); } @@ -271,8 +271,8 @@ public void ShouldRegisterTheOverriddenAssemblyUtility() { var mock = new Mock(); _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -281,8 +281,8 @@ public void ShouldRegisterTheOverriddenPackageContainer() { var mock = new Mock(); _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -291,8 +291,8 @@ public void ShouldRegisterTheOverriddenPackageAssemblyResolver() { var mock = new Mock(); _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -301,8 +301,8 @@ public void ShouldRegisterTheOverriddenAssemblyResolver() { var mock = new Mock(); _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -311,8 +311,8 @@ public void ShouldRegisterTheOverriddenAssemblyResolverInstance() { var mock = new Mock(); _overrides[typeof(IAssemblyResolver)] = mock.Object; - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldEqual(mock.Object); } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 62553def..00ce9fa0 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -25,7 +25,7 @@ public void ShouldDeletePackagesFolder() var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 353d9030..4ad4bfd5 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -11,7 +11,7 @@ public class CommandFactoryTests { public class CreateCommandMethod { - private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool packagesFolderExists = true) + private static ScriptServices CreateRoot(bool packagesFileExists = true, bool packagesFolderExists = true) { const string CurrentDirectory = "C:\\"; const string PackagesFile = "C:\\packages.config"; @@ -31,7 +31,7 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index d86e3ed0..17ecd72a 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -27,7 +27,7 @@ public void ShouldPromptForInput() var console = new FakeConsole(writer, reader); - var root = new ScriptServiceRoot( + var root = new ScriptServices( mockFileSystem.Object, Mock.Of(), Mock.Of(), diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c3363161..96c4f1b1 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -36,7 +36,7 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -76,7 +76,7 @@ public void NonManagedAssembliesAreExcluded() var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); @@ -113,7 +113,7 @@ public void ShouldReturnErrorIfThereIsCompileException() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -148,7 +148,7 @@ public void ShouldReturnErrorIfThereIsExecuteException() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index c1e4efaa..505e6d22 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -38,7 +38,7 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -72,7 +72,7 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 8546f5e8..462cbe5e 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -43,7 +43,7 @@ public void VersionCommandShouldOutputVersion() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); From dc298a6c8f7c63839f93412846a4a240aef53a79 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 14:49:30 -0700 Subject: [PATCH 0342/1224] removing user files and adding to .gitignore --- .gitignore | 1 + ScriptCs.sln.ide/graph/ScriptCs.sln.ide | 3 -- scriptcs_debug.sln | 37 ------------------------- 3 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 ScriptCs.sln.ide/graph/ScriptCs.sln.ide delete mode 100644 scriptcs_debug.sln diff --git a/.gitignore b/.gitignore index 362c5a12..ffd6105f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ TestResults *.suo *.user *.sln.docstates +*.sln.ide # Build results [Dd]ebug/ diff --git a/ScriptCs.sln.ide/graph/ScriptCs.sln.ide b/ScriptCs.sln.ide/graph/ScriptCs.sln.ide deleted file mode 100644 index 4b1badd9..00000000 --- a/ScriptCs.sln.ide/graph/ScriptCs.sln.ide +++ /dev/null @@ -1,3 +0,0 @@ - - 0001-01-01T00:00:00Z - \ No newline at end of file diff --git a/scriptcs_debug.sln b/scriptcs_debug.sln deleted file mode 100644 index 24e9cece..00000000 --- a/scriptcs_debug.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "scriptcs", "src\ScriptCs\bin\Debug\scriptcs.exe", "{D797ABD7-8971-4227-B9C4-8ECC158FD12B}" - ProjectSection(DebuggerProjectSystem) = preProject - PortSupplier = 00000000-0000-0000-0000-000000000000 - Executable = C:\code\scriptcs\src\ScriptCs\bin\Debug\scriptcs.exe - RemoteMachine = GBLOCK-WIN8 - StartingDirectory = C:\code\scriptcs-samples\wpf - Arguments = start.csx -debug - Environment = Default - LaunchingEngine = 00000000-0000-0000-0000-000000000000 - LaunchSQLEngine = No - AttachLaunchAction = No - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39CDE834-543F-4352-AF43-F1CA3D6CCBFF}" - ProjectSection(SolutionItems) = preProject - ..\scriptcs-samples\wpf\CalculatorView.xaml = ..\scriptcs-samples\wpf\CalculatorView.xaml - ..\scriptcs-samples\wpf\mvvm.csx = ..\scriptcs-samples\wpf\mvvm.csx - ..\scriptcs-samples\wpf\start.csx = ..\scriptcs-samples\wpf\start.csx - ..\scriptcs-samples\wpf\utilities.csx = ..\scriptcs-samples\wpf\utilities.csx - ..\scriptcs-samples\wpf\viewmodels.csx = ..\scriptcs-samples\wpf\viewmodels.csx - ..\scriptcs-samples\wpf\views.csx = ..\scriptcs-samples\wpf\views.csx - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D797ABD7-8971-4227-B9C4-8ECC158FD12B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal From 88f64542b71335e1f9604d824355e166ecc26a9d Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 26 Jun 2013 00:13:38 -0700 Subject: [PATCH 0343/1224] Adding the new Host project with a ScriptRuntimeBuilder. Bunch of refactoring to make ScriptCs project even lighter --- .../ScriptCs => ScriptCs.Hosting}/LogLevel.cs | 0 .../LoggerConfigurator.cs | 2 +- .../ScriptConsole.cs | 0 .../ScriptConsoleAppender.cs | 4 +- ScriptCs.Hosting/ScriptCs.Hosting.csproj | 91 +++++++++++++++++++ ScriptCs.Hosting/ScriptRuntimeBuilder.cs | 63 +++++++++++++ ScriptCs.Hosting/packages.config | 6 ++ ScriptCs.sln | 6 ++ src/ScriptCs/Program.cs | 31 +++---- src/ScriptCs/ScriptCs.csproj | 8 +- 10 files changed, 184 insertions(+), 27 deletions(-) rename {src/ScriptCs => ScriptCs.Hosting}/LogLevel.cs (100%) rename {src/ScriptCs => ScriptCs.Hosting}/LoggerConfigurator.cs (96%) rename {src/ScriptCs => ScriptCs.Hosting}/ScriptConsole.cs (100%) rename src/ScriptCs/ScriptcsConsoleAppender.cs => ScriptCs.Hosting/ScriptConsoleAppender.cs (81%) create mode 100644 ScriptCs.Hosting/ScriptCs.Hosting.csproj create mode 100644 ScriptCs.Hosting/ScriptRuntimeBuilder.cs create mode 100644 ScriptCs.Hosting/packages.config diff --git a/src/ScriptCs/LogLevel.cs b/ScriptCs.Hosting/LogLevel.cs similarity index 100% rename from src/ScriptCs/LogLevel.cs rename to ScriptCs.Hosting/LogLevel.cs diff --git a/src/ScriptCs/LoggerConfigurator.cs b/ScriptCs.Hosting/LoggerConfigurator.cs similarity index 96% rename from src/ScriptCs/LoggerConfigurator.cs rename to ScriptCs.Hosting/LoggerConfigurator.cs index 2b4e6d92..06bab269 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/ScriptCs.Hosting/LoggerConfigurator.cs @@ -29,7 +29,7 @@ public void Configure(IConsole console) { var hierarchy = (Hierarchy)LogManager.GetRepository(); var logger = LogManager.GetLogger(LoggerName); - var consoleAppender = new ScriptcsConsoleAppender(console) + var consoleAppender = new ScriptConsoleAppender(console) { Layout = new PatternLayout(GetLogPattern(_logLevel)), Threshold = hierarchy.LevelMap[_logLevel.ToString().ToUpper(CultureInfo.CurrentCulture)] diff --git a/src/ScriptCs/ScriptConsole.cs b/ScriptCs.Hosting/ScriptConsole.cs similarity index 100% rename from src/ScriptCs/ScriptConsole.cs rename to ScriptCs.Hosting/ScriptConsole.cs diff --git a/src/ScriptCs/ScriptcsConsoleAppender.cs b/ScriptCs.Hosting/ScriptConsoleAppender.cs similarity index 81% rename from src/ScriptCs/ScriptcsConsoleAppender.cs rename to ScriptCs.Hosting/ScriptConsoleAppender.cs index f250e7f5..b0867ea1 100644 --- a/src/ScriptCs/ScriptcsConsoleAppender.cs +++ b/ScriptCs.Hosting/ScriptConsoleAppender.cs @@ -5,11 +5,11 @@ namespace ScriptCs { - public class ScriptcsConsoleAppender : AppenderSkeleton + public class ScriptConsoleAppender : AppenderSkeleton { private readonly IConsole _console; - public ScriptcsConsoleAppender(IConsole console) + public ScriptConsoleAppender(IConsole console) { _console = console; } diff --git a/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/ScriptCs.Hosting/ScriptCs.Hosting.csproj new file mode 100644 index 00000000..969ac0cf --- /dev/null +++ b/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -0,0 +1,91 @@ + + + + + Debug + AnyCPU + {9AEF2D95-87FB-4829-B384-34BFE076D531} + Library + Properties + ScriptCs.Hosting + ScriptCs.Hosting + v4.5 + 512 + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll + + + ..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll + + + ..\packages\log4net.1.2.10\lib\2.0\log4net.dll + + + + + + + + + + + + {6049e205-8b5f-4080-b023-70600e51fd64} + ScriptCs.Contracts + + + {e590e710-e159-48e6-a3e6-1a83d3fe732c} + ScriptCs.Core + + + {e79ec231-e27d-4057-91c9-2d001a3a8c3b} + ScriptCs.Engine.Roslyn + + + + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/ScriptCs.Hosting/ScriptRuntimeBuilder.cs new file mode 100644 index 00000000..27894868 --- /dev/null +++ b/ScriptCs.Hosting/ScriptRuntimeBuilder.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Engine.Roslyn; + +namespace ScriptCs +{ + public class ScriptRuntimeBuilder + { + private bool _debug = false; + private bool _repl = false; + private string _scriptName; + private LogLevel _logLevel; + + public ScriptRuntime Build() + { + Type scriptExecutorType; + Type scriptEngineType; + + if (_debug) + { + scriptExecutorType = typeof(DebugScriptExecutor); + scriptEngineType = typeof(RoslynScriptDebuggerEngine); + } + else + { + scriptExecutorType = typeof(ScriptExecutor); + scriptEngineType = typeof(RoslynScriptEngine); + } + + var loggerConfigurator = new LoggerConfigurator(_logLevel); + + var runtime = new ScriptRuntime(_scriptName, _repl, loggerConfigurator, new ScriptConsole(), scriptExecutorType, scriptEngineType); + return runtime; + } + + public ScriptRuntimeBuilder Debug(bool debug = true) + { + _debug = debug; + return this; + } + + public ScriptRuntimeBuilder ScriptName(string name) + { + _scriptName = name; + return this; + } + + public ScriptRuntimeBuilder Repl(bool repl = true) + { + _repl = repl; + return this; + } + + public ScriptRuntimeBuilder LogLevel(LogLevel level) + { + _logLevel = level; + return this; + } + } +} diff --git a/ScriptCs.Hosting/packages.config b/ScriptCs.Hosting/packages.config new file mode 100644 index 00000000..8ec4ed08 --- /dev/null +++ b/ScriptCs.Hosting/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ScriptCs.sln b/ScriptCs.sln index 79d00af5..22eac033 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn", "s EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn.Tests", "test\ScriptCs.Engine.Roslyn.Tests\ScriptCs.Engine.Roslyn.Tests.csproj", "{28D11DE5-9F98-4E0A-8CCC-9CDC19110451}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting", "ScriptCs.Hosting\ScriptCs.Hosting.csproj", "{9AEF2D95-87FB-4829-B384-34BFE076D531}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +69,10 @@ Global {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Debug|Any CPU.Build.0 = Debug|Any CPU {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Release|Any CPU.ActiveCfg = Release|Any CPU {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Release|Any CPU.Build.0 = Release|Any CPU + {9AEF2D95-87FB-4829-B384-34BFE076D531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AEF2D95-87FB-4829-B384-34BFE076D531}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AEF2D95-87FB-4829-B384-34BFE076D531}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AEF2D95-87FB-4829-B384-34BFE076D531}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index ca1d0b28..c635f873 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -13,31 +13,22 @@ private static int Main(string[] args) { string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Type scriptExecutorType; - Type scriptEngineType; - + var commandArgs = ParseArguments(args); - - if (commandArgs.Debug) - { - scriptExecutorType = typeof (DebugScriptExecutor); - scriptEngineType = typeof (RoslynScriptDebuggerEngine); - } - else - { - scriptExecutorType = typeof (ScriptExecutor); - scriptEngineType = typeof (RoslynScriptEngine); - } - var loggerConfigurator = new LoggerConfigurator(commandArgs.LogLevel); - - var compositionRoot = new ScriptRuntime(commandArgs.ScriptName, commandArgs.Repl,loggerConfigurator,new ScriptConsole(), scriptExecutorType, scriptEngineType); - compositionRoot.Initialize(); + var runtime = new ScriptRuntimeBuilder(). + Debug(commandArgs.Debug). + LogLevel(commandArgs.LogLevel). + ScriptName(commandArgs.ScriptName). + Repl(commandArgs.Repl). + Build(); + + runtime.Initialize(); - var logger = compositionRoot.GetLogger(); + var logger = runtime.GetLogger(); logger.Debug("Creating ScriptServices"); - var scriptServiceRoot = compositionRoot.GetScriptServices(); + var scriptServiceRoot = runtime.GetScriptServices(); var commandFactory = new CommandFactory(scriptServiceRoot); var command = commandFactory.CreateCommand(commandArgs, scriptArgs); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index fcdb9c82..08c6c705 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -73,11 +73,7 @@ - - - - @@ -89,6 +85,10 @@ + + {9aef2d95-87fb-4829-b384-34bfe076d531} + ScriptCs.Hosting + {6049e205-8b5f-4080-b023-70600e51fd64} ScriptCs.Contracts From b31cade3dbc72a4b0247dd4342054c6e4b846ad2 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 26 Jun 2013 00:51:15 -0700 Subject: [PATCH 0344/1224] Adding override methods to builder --- ScriptCs.Hosting/ScriptRuntimeBuilder.cs | 97 ++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 8 deletions(-) diff --git a/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/ScriptCs.Hosting/ScriptRuntimeBuilder.cs index 27894868..89f4bf70 100644 --- a/ScriptCs.Hosting/ScriptRuntimeBuilder.cs +++ b/ScriptCs.Hosting/ScriptRuntimeBuilder.cs @@ -4,6 +4,8 @@ using System.Text; using System.Threading.Tasks; using ScriptCs.Engine.Roslyn; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; namespace ScriptCs { @@ -13,26 +15,32 @@ public class ScriptRuntimeBuilder private bool _repl = false; private string _scriptName; private LogLevel _logLevel; + private IDictionary _overrides = new Dictionary(); + private Type _scriptExecutorType; + private Type _scriptEngineType; public ScriptRuntime Build() { - Type scriptExecutorType; - Type scriptEngineType; - if (_debug) { - scriptExecutorType = typeof(DebugScriptExecutor); - scriptEngineType = typeof(RoslynScriptDebuggerEngine); + if (_scriptExecutorType == null) + _scriptExecutorType = typeof(DebugScriptExecutor); + + if (_scriptEngineType == null) + _scriptEngineType = typeof(RoslynScriptDebuggerEngine); } else { - scriptExecutorType = typeof(ScriptExecutor); - scriptEngineType = typeof(RoslynScriptEngine); + if (_scriptExecutorType == null) + _scriptExecutorType = typeof(ScriptExecutor); + + if (_scriptEngineType == null) + _scriptEngineType = typeof(RoslynScriptEngine); } var loggerConfigurator = new LoggerConfigurator(_logLevel); - var runtime = new ScriptRuntime(_scriptName, _repl, loggerConfigurator, new ScriptConsole(), scriptExecutorType, scriptEngineType); + var runtime = new ScriptRuntime(_scriptName, _repl, loggerConfigurator, new ScriptConsole(), _scriptExecutorType, _scriptEngineType, _overrides); return runtime; } @@ -59,5 +67,78 @@ public ScriptRuntimeBuilder LogLevel(LogLevel level) _logLevel = level; return this; } + + public ScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor + { + _scriptExecutorType = typeof (T); + return this; + } + + public ScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine + { + _scriptEngineType = typeof(T); + return this; + } + + public ScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory + { + _overrides[typeof(IScriptHostFactory)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager + { + _overrides[typeof(IScriptPackManager)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver + { + _overrides[typeof(IScriptPackResolver)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider + { + _overrides[typeof(IInstallationProvider)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder FileSystem() where T : IFileSystem + { + _overrides[typeof(IFileSystem)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility + { + _overrides[typeof(IAssemblyUtility)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder PackageContainer() where T : IPackageContainer + { + _overrides[typeof(IPackageContainer)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor + { + _overrides[typeof(IFilePreProcessor)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver + { + _overrides[typeof(IPackageAssemblyResolver)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor + { + _overrides[typeof(IAssemblyResolver)] = typeof(T); + return this; + } + } } From 38cf679afa58d050506c9d1c1f74288c9766a9fa Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 25 Jun 2013 09:58:26 -0700 Subject: [PATCH 0345/1224] VersionCommand should depend on IConsole --- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/Command/VersionCommand.cs | 14 ++++++-- test/ScriptCs.Tests/VersionCommandTests.cs | 38 ++++++++-------------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index fb077817..082baea6 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -107,7 +107,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Version) { - return new VersionCommand(); + return new VersionCommand(_scriptServices.Console); } return new ShowUsageCommand(_scriptServices.Logger, isValid: false); diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index d51b4a0a..d8264c36 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -1,12 +1,22 @@ -using System; +using System.Diagnostics; +using ScriptCs.Contracts; namespace ScriptCs.Command { internal class VersionCommand : IVersionCommand { + private readonly IConsole _console; + + public VersionCommand(IConsole console) + { + _console = console; + } + public CommandResult Execute() { - Console.WriteLine("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + var message = string.Format("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + _console.WriteLine(message); + return CommandResult.Success; } } diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 462cbe5e..029d1eb2 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -1,6 +1,8 @@ -using Common.Logging; +using System.Diagnostics; +using Common.Logging; using Moq; using ScriptCs.Command; +using ScriptCs.Contracts; using ScriptCs.Package; using System.IO; using Xunit; @@ -11,28 +13,15 @@ public class VersionCommandTests { public class ExecuteMethod { - private readonly System.Version _currentVersion; - - System.Text.StringBuilder _outputText; - StringWriter _mockConsole; - TextWriter _actualConsole; - - public ExecuteMethod() - { - _currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - _outputText = new System.Text.StringBuilder(); - _mockConsole = new StringWriter(_outputText); - _actualConsole = System.Console.Out; - System.Console.SetOut(_mockConsole); - } - [Fact] public void VersionCommandShouldOutputVersion() { - var args = new ScriptCsArgs - { - Version = true - }; + var assembly = typeof(ScriptCsArgs).Assembly; + var version = assembly.GetName().Version.ToString(); + + string actual = null; + + var args = new ScriptCsArgs { Version = true }; var fs = new Mock(); var resolver = new Mock(); @@ -43,17 +32,16 @@ public void VersionCommandShouldOutputVersion() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var mockConsole = new Mock(); + mockConsole.Setup(x => x.WriteLine(It.IsAny())).Callback(text => actual = text); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object, mockConsole.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); - // clear the fake console output - _outputText.Clear(); - result.Execute(); - Assert.Contains("scriptcs version " + _currentVersion.ToString(), _outputText.ToString()); + Assert.Contains(version, actual); } } } From 90909caa49ff44ecbe2f02f873e0a2e9bc996b3d Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 25 Jun 2013 09:59:49 -0700 Subject: [PATCH 0346/1224] VersionCommand should write the product version --- src/ScriptCs/Command/VersionCommand.cs | 5 ++++- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index d8264c36..1ed1e9b2 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -14,7 +14,10 @@ public VersionCommand(IConsole console) public CommandResult Execute() { - var message = string.Format("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + var assembly = typeof(Program).Assembly; + var productVersion = FileVersionInfo.GetVersionInfo(assembly.Location).ProductVersion; + var message = string.Format("scriptcs v{0}", productVersion); + _console.WriteLine(message); return CommandResult.Success; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 029d1eb2..70e4b967 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -17,7 +17,7 @@ public class ExecuteMethod public void VersionCommandShouldOutputVersion() { var assembly = typeof(ScriptCsArgs).Assembly; - var version = assembly.GetName().Version.ToString(); + var version = FileVersionInfo.GetVersionInfo(assembly.Location).ProductVersion; string actual = null; From b6c06ad11766630c93d130dd0f62f51e8bb1012f Mon Sep 17 00:00:00 2001 From: Filip W Date: Wed, 26 Jun 2013 20:44:12 +0200 Subject: [PATCH 0347/1224] updated to support Repl multi line --- src/ScriptCs.Core/Repl.cs | 25 ++++++++++++++++--- src/ScriptCs.Core/ScriptResult.cs | 22 ++++++++++++++++ .../RoslynScriptEngine.cs | 4 ++- src/ScriptCs/Command/ExecuteReplCommand.cs | 5 ++-- 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 7beeb1a5..89960a1a 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -24,6 +24,8 @@ public override void Terminate() Console.Exit(); } + public string Buffer { get; set; } + public override ScriptResult Execute(string script) { try @@ -50,8 +52,17 @@ public override ScriptResult Execute(string script) return new ScriptResult(); } + //if (!script.EndsWith(";")) + //{ + // Buffer += script; + // return new ScriptResult(); + //} + Console.ForegroundColor = ConsoleColor.Cyan; - var result = ScriptEngine.Execute(script, new string[0], References, DefaultNamespaces, ScriptPackSession); + + Buffer += script; + + var result = ScriptEngine.Execute(Buffer, new string[0], References, DefaultNamespaces, ScriptPackSession); if (result != null) { if (result.CompileException != null) @@ -66,8 +77,16 @@ public override ScriptResult Execute(string script) Console.Write(result.ExecuteException.ToString()); } - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ReturnValue.ToJsv()); + if (result.IsPendingClosingChar) + { + return result; + } + else + { + Buffer = null; + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(result.ReturnValue.ToJsv()); + } } return result; diff --git a/src/ScriptCs.Core/ScriptResult.cs b/src/ScriptCs.Core/ScriptResult.cs index 10933f69..c34c26c0 100644 --- a/src/ScriptCs.Core/ScriptResult.cs +++ b/src/ScriptCs.Core/ScriptResult.cs @@ -9,5 +9,27 @@ public class ScriptResult public Exception ExecuteException { get; set; } public Exception CompileException { get; set; } + + public bool ContinueBuffering { get; set; } + + public bool IsPendingClosingChar { get; set; } + + public char? ExpectingClosingChar { get; set; } + + public void UpdateClosingExpectation(Exception ex) + { + var message = ex.Message; + char? closingChar = null; + + if (message.Contains("CS1026: ) expected")) + closingChar = ')'; + else if (message.Contains("CS1513: } expected")) + closingChar = '}'; + else if (message.Contains("CS1003: Syntax error, ']' expected")) + closingChar = ']'; + + ExpectingClosingChar = closingChar; + IsPendingClosingChar = closingChar.HasValue; + } } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 6ae75a46..f15341c3 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -102,7 +102,9 @@ protected virtual ScriptResult Execute(string code, Session session) } catch (Exception ex) { - result.CompileException = ex; + result.UpdateClosingExpectation(ex); + if (!result.IsPendingClosingChar) + result.CompileException = ex; } return result; } diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 95d5d3ed..2d1adee4 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -68,10 +68,11 @@ public CommandResult Execute() private bool ExecuteLine(Repl repl) { - _console.Write("> "); + if (string.IsNullOrWhiteSpace(repl.Buffer)) + _console.Write("> "); var line = _console.ReadLine(); - if (line == string.Empty) return false; + if (line == string.Empty && string.IsNullOrWhiteSpace(repl.Buffer)) return false; repl.Execute(line); return true; From 33ae6840ce9ac9f72695a209ee1a8c017ddd7b39 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 12:00:17 -0700 Subject: [PATCH 0348/1224] Move ScriptCs.Hosting project into the src folder --- ScriptCs.sln | 2 +- .../ScriptCs.Hosting}/LogLevel.cs | 0 .../ScriptCs.Hosting}/LoggerConfigurator.cs | 0 .../ScriptCs.Hosting}/ScriptConsole.cs | 0 .../ScriptCs.Hosting}/ScriptConsoleAppender.cs | 0 .../ScriptCs.Hosting}/ScriptCs.Hosting.csproj | 16 ++++++++-------- .../ScriptCs.Hosting}/ScriptRuntimeBuilder.cs | 0 .../ScriptCs.Hosting}/packages.config | 0 src/ScriptCs/ScriptCs.csproj | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/LogLevel.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/LoggerConfigurator.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/ScriptConsole.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/ScriptConsoleAppender.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/ScriptCs.Hosting.csproj (84%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/ScriptRuntimeBuilder.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/packages.config (100%) diff --git a/ScriptCs.sln b/ScriptCs.sln index 22eac033..70adc0fa 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -33,7 +33,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn", "s EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn.Tests", "test\ScriptCs.Engine.Roslyn.Tests\ScriptCs.Engine.Roslyn.Tests.csproj", "{28D11DE5-9F98-4E0A-8CCC-9CDC19110451}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting", "ScriptCs.Hosting\ScriptCs.Hosting.csproj", "{9AEF2D95-87FB-4829-B384-34BFE076D531}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting", "src\ScriptCs.Hosting\ScriptCs.Hosting.csproj", "{9AEF2D95-87FB-4829-B384-34BFE076D531}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/ScriptCs.Hosting/LogLevel.cs b/src/ScriptCs.Hosting/LogLevel.cs similarity index 100% rename from ScriptCs.Hosting/LogLevel.cs rename to src/ScriptCs.Hosting/LogLevel.cs diff --git a/ScriptCs.Hosting/LoggerConfigurator.cs b/src/ScriptCs.Hosting/LoggerConfigurator.cs similarity index 100% rename from ScriptCs.Hosting/LoggerConfigurator.cs rename to src/ScriptCs.Hosting/LoggerConfigurator.cs diff --git a/ScriptCs.Hosting/ScriptConsole.cs b/src/ScriptCs.Hosting/ScriptConsole.cs similarity index 100% rename from ScriptCs.Hosting/ScriptConsole.cs rename to src/ScriptCs.Hosting/ScriptConsole.cs diff --git a/ScriptCs.Hosting/ScriptConsoleAppender.cs b/src/ScriptCs.Hosting/ScriptConsoleAppender.cs similarity index 100% rename from ScriptCs.Hosting/ScriptConsoleAppender.cs rename to src/ScriptCs.Hosting/ScriptConsoleAppender.cs diff --git a/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj similarity index 84% rename from ScriptCs.Hosting/ScriptCs.Hosting.csproj rename to src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index 969ac0cf..c1cde3ee 100644 --- a/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -33,13 +33,13 @@ - ..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll - ..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll + ..\..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll - ..\packages\log4net.1.2.10\lib\2.0\log4net.dll + ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll @@ -50,24 +50,24 @@ - + {6049e205-8b5f-4080-b023-70600e51fd64} ScriptCs.Contracts - + {e590e710-e159-48e6-a3e6-1a83d3fe732c} ScriptCs.Core - + {e79ec231-e27d-4057-91c9-2d001a3a8c3b} ScriptCs.Engine.Roslyn - + Properties\CommonAssemblyInfo.cs - + Properties\CommonVersionInfo.cs diff --git a/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs similarity index 100% rename from ScriptCs.Hosting/ScriptRuntimeBuilder.cs rename to src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs diff --git a/ScriptCs.Hosting/packages.config b/src/ScriptCs.Hosting/packages.config similarity index 100% rename from ScriptCs.Hosting/packages.config rename to src/ScriptCs.Hosting/packages.config diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 08c6c705..ac3e3e66 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -85,7 +85,7 @@ - + {9aef2d95-87fb-4829-b384-34bfe076d531} ScriptCs.Hosting From d7525959ef3d65b0388fd13a566df19c51cd1230 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 12:09:24 -0700 Subject: [PATCH 0349/1224] Add AssemblyInfo.cs to the ScriptCs.Hosting project --- src/ScriptCs.Hosting/Properties/AssemblyInfo.cs | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/ScriptCs.Hosting/Properties/AssemblyInfo.cs diff --git a/src/ScriptCs.Hosting/Properties/AssemblyInfo.cs b/src/ScriptCs.Hosting/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..27c64e7e --- /dev/null +++ b/src/ScriptCs.Hosting/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Reflection; + +[assembly: AssemblyTitle("ScriptCs.Hosting")] +[assembly: AssemblyDescription("ScriptCs.Hosting provides common services necessary for hosting scriptcs in your application.")] From 8ed5ed2cf5c2aa22bb08f937162dbaafc1dac942 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 12:21:45 -0700 Subject: [PATCH 0350/1224] ScriptCs.Hosting should use the common build settings defined by the build script --- src/ScriptCs.Hosting/ScriptCs.Hosting.csproj | 26 ++------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index c1cde3ee..f6c02dd1 100644 --- a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -1,35 +1,12 @@  - + - Debug - AnyCPU {9AEF2D95-87FB-4829-B384-34BFE076D531} Library - Properties ScriptCs.Hosting ScriptCs.Hosting - v4.5 - 512 ..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 @@ -72,6 +49,7 @@ + From 30ff9d937087d41e3b8a4704cc8f1a724b023cc1 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 13:04:43 -0700 Subject: [PATCH 0351/1224] Create a nuspec file for ScriptCs.Hosting --- build/Build.proj | 1 + .../Properties/ScriptCs.Hosting.nuspec | 14 ++++++++++++++ src/ScriptCs.Hosting/ScriptCs.Hosting.csproj | 1 + 3 files changed, 16 insertions(+) create mode 100644 src/ScriptCs.Hosting/Properties/ScriptCs.Hosting.nuspec diff --git a/build/Build.proj b/build/Build.proj index 1c340e06..679c3aee 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -79,6 +79,7 @@ + diff --git a/src/ScriptCs.Hosting/Properties/ScriptCs.Hosting.nuspec b/src/ScriptCs.Hosting/Properties/ScriptCs.Hosting.nuspec new file mode 100644 index 00000000..896e7dbb --- /dev/null +++ b/src/ScriptCs.Hosting/Properties/ScriptCs.Hosting.nuspec @@ -0,0 +1,14 @@ + + + + ScriptCs.Hosting + 0.0.0 + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md + http://scriptcs.net + http://www.gravatar.com/avatar/5c754f646971d8bc800b9d4057931938.png?s=120 + ScriptCs.Hosting provides common services necessary for hosting scriptcs in your application. + roslyn csx script scriptcs + + \ No newline at end of file diff --git a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index f6c02dd1..7acdba64 100644 --- a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -56,6 +56,7 @@ + From 692bda054d350a8f835c39ded31b7d8c15fae14a Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 14:26:16 -0700 Subject: [PATCH 0352/1224] Create a test project for ScriptCs.Hosting --- ScriptCs.sln | 7 ++++ .../Properties/AssemblyInfo.cs | 4 ++ .../ScriptCs.Hosting.Tests.csproj | 40 +++++++++++++++++++ test/ScriptCs.Hosting.Tests/packages.config | 4 ++ 4 files changed, 55 insertions(+) create mode 100644 test/ScriptCs.Hosting.Tests/Properties/AssemblyInfo.cs create mode 100644 test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj create mode 100644 test/ScriptCs.Hosting.Tests/packages.config diff --git a/ScriptCs.sln b/ScriptCs.sln index 70adc0fa..506cc3c3 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn.Test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting", "src\ScriptCs.Hosting\ScriptCs.Hosting.csproj", "{9AEF2D95-87FB-4829-B384-34BFE076D531}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting.Tests", "test\ScriptCs.Hosting.Tests\ScriptCs.Hosting.Tests.csproj", "{EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -73,6 +75,10 @@ Global {9AEF2D95-87FB-4829-B384-34BFE076D531}.Debug|Any CPU.Build.0 = Debug|Any CPU {9AEF2D95-87FB-4829-B384-34BFE076D531}.Release|Any CPU.ActiveCfg = Release|Any CPU {9AEF2D95-87FB-4829-B384-34BFE076D531}.Release|Any CPU.Build.0 = Release|Any CPU + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -81,5 +87,6 @@ Global {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} {AC228213-7356-4F0D-BA48-EBA5FB8A7506} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} {28D11DE5-9F98-4E0A-8CCC-9CDC19110451} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} EndGlobalSection EndGlobal diff --git a/test/ScriptCs.Hosting.Tests/Properties/AssemblyInfo.cs b/test/ScriptCs.Hosting.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d1a57655 --- /dev/null +++ b/test/ScriptCs.Hosting.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Reflection; + +[assembly: AssemblyTitle("ScriptCs.Hosting.Tests")] +[assembly: AssemblyDescription("")] diff --git a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj new file mode 100644 index 00000000..54bed027 --- /dev/null +++ b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj @@ -0,0 +1,40 @@ + + + + + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A} + Library + Properties + ScriptCs.Hosting.Tests + ScriptCs.Hosting.Tests + ..\..\ + + + + + + + ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + + + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + + + + + + + + + {9aef2d95-87fb-4829-b384-34bfe076d531} + ScriptCs.Hosting + + + + + \ No newline at end of file diff --git a/test/ScriptCs.Hosting.Tests/packages.config b/test/ScriptCs.Hosting.Tests/packages.config new file mode 100644 index 00000000..7c4280d1 --- /dev/null +++ b/test/ScriptCs.Hosting.Tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 73283c53a7670ea2281a09e77012b811616094b7 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 28 Jun 2013 23:15:05 -0700 Subject: [PATCH 0353/1224] Settings services to be singletons, fix for #360 --- src/ScriptCs.Core/ScriptRuntime.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/ScriptRuntime.cs b/src/ScriptCs.Core/ScriptRuntime.cs index 6d073ffd..a88191c2 100644 --- a/src/ScriptCs.Core/ScriptRuntime.cs +++ b/src/ScriptCs.Core/ScriptRuntime.cs @@ -67,7 +67,7 @@ public void RegisterOverrideOrDefault(ContainerBuilder builder, Action(); + builder.RegisterType((Type)reg).As().SingleInstance(); } else { From eac02b2bbb94441ac286e66aa52df09db1fec17e Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 6 Jul 2013 08:32:25 +0200 Subject: [PATCH 0354/1224] Added tests for REPL multiline --- src/ScriptCs.Core/Repl.cs | 6 -- test/ScriptCs.Core.Tests/ReplTests.cs | 42 +++++++++++++ .../RoslynScriptEngineTests.cs | 63 +++++++++++++++++++ 3 files changed, 105 insertions(+), 6 deletions(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 89960a1a..076be474 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -52,12 +52,6 @@ public override ScriptResult Execute(string script) return new ScriptResult(); } - //if (!script.EndsWith(";")) - //{ - // Buffer += script; - // return new ScriptResult(); - //} - Console.ForegroundColor = ConsoleColor.Cyan; Buffer += script; diff --git a/test/ScriptCs.Core.Tests/ReplTests.cs b/test/ScriptCs.Core.Tests/ReplTests.cs index ac977553..ce8c4d5a 100644 --- a/test/ScriptCs.Core.Tests/ReplTests.cs +++ b/test/ScriptCs.Core.Tests/ReplTests.cs @@ -303,6 +303,48 @@ public void ShouldNotExecuteAnythingIfLineIsAReference() mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); } + + [Fact] + public void ShouldSetBufferIFLineIsFirstOfMultilineConstruct() + { + var mocks = new Mocks(); + mocks.ScriptEngine.Setup( + x => + x.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Returns(x => new ScriptResult() + { + ExpectingClosingChar = ')', + IsPendingClosingChar = true + }); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("var x = 1;"); + + _repl.Buffer.ShouldNotBeNull(); + } + + [Fact] + public void ShouldResetSetBufferIFLineIsBoLongerMultilineConstruct() + { + var mocks = new Mocks(); + mocks.ScriptEngine.Setup( + x => + x.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Returns(new ScriptResult + { + IsPendingClosingChar = false + }); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + _repl = GetRepl(mocks); + _repl.Buffer = "class test {"; + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("}"); + + _repl.Buffer.ShouldBeNull(); + } } } } diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index fc013f64..fc272900 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -245,6 +245,69 @@ public void ShouldNotReturnReturnValueIfCodeExecutionDoesNotReturnValue() result.ReturnValue.ShouldBeNull(); } + + [Fact] + public void ShouldSetIsPendingClosingCharToTrueIfCodeIsMissingCurlyBracket() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())) + .Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "class test {"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState {Session = roslynEngine.CreateSession()}; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] {"System"}, Enumerable.Empty(), + scriptPackSession); + + result.IsPendingClosingChar.ShouldBeTrue(); + result.ExpectingClosingChar.ShouldEqual('}'); + } + + [Fact] + public void ShouldSetIsPendingClosingCharToTrueIfCodeIsMissingSquareBracket() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())) + .Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "var x = new[1] { 1}; var y = x[0"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), + scriptPackSession); + + result.IsPendingClosingChar.ShouldBeTrue(); + result.ExpectingClosingChar.ShouldEqual(']'); + } + + [Fact] + public void ShouldSetIsPendingClosingCharToTrueIfCodeIsMissingParenthesis() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())) + .Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "System.Diagnostics.Debug.WriteLine(\"a\""; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), + scriptPackSession); + + result.IsPendingClosingChar.ShouldBeTrue(); + result.ExpectingClosingChar.ShouldEqual(')'); + } } } } \ No newline at end of file From 7319e26c557562c923686cc67a479380a910f6de Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 6 Jul 2013 08:39:17 +0200 Subject: [PATCH 0355/1224] added test to verify the overall resubmission --- test/ScriptCs.Core.Tests/ReplTests.cs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/test/ScriptCs.Core.Tests/ReplTests.cs b/test/ScriptCs.Core.Tests/ReplTests.cs index ce8c4d5a..69635434 100644 --- a/test/ScriptCs.Core.Tests/ReplTests.cs +++ b/test/ScriptCs.Core.Tests/ReplTests.cs @@ -326,7 +326,7 @@ public void ShouldSetBufferIFLineIsFirstOfMultilineConstruct() } [Fact] - public void ShouldResetSetBufferIFLineIsBoLongerMultilineConstruct() + public void ShouldResetBufferIfLineIsNoLongerMultilineConstruct() { var mocks = new Mocks(); mocks.ScriptEngine.Setup( @@ -345,6 +345,27 @@ public void ShouldResetSetBufferIFLineIsBoLongerMultilineConstruct() _repl.Buffer.ShouldBeNull(); } + + [Fact] + public void ShouldResubmitEverytingIfLineIsNoLongerMultilineConstruct() + { + var mocks = new Mocks(); + mocks.ScriptEngine.Setup( + x => + x.Execute(It.Is(i => i == "class test {}"), It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Returns(new ScriptResult + { + IsPendingClosingChar = false + }); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + _repl = GetRepl(mocks); + _repl.Buffer = "class test {"; + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("}"); + + mocks.ScriptEngine.Verify(); + } } } } From e4a8338ad8f5530273510aad7447e88efbef2ca0 Mon Sep 17 00:00:00 2001 From: lbargaoanu Date: Mon, 15 Jul 2013 15:38:07 +0300 Subject: [PATCH 0356/1224] Allow adding namespaces and refrences to script executor without having to create a script pack Issue #327 --- src/ScriptCs.Core/Repl.cs | 7 +- src/ScriptCs.Core/ScriptExecutor.cs | 81 ++++++++++++++++++- .../ScriptExecutorTests.cs | 47 ++++++++++- 3 files changed, 122 insertions(+), 13 deletions(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 076be474..fd5721ee 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -47,7 +47,7 @@ public override ScriptResult Execute(string script) { var assemblyName = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); var assemblyPath = FileSystem.GetFullPath(Path.Combine(Constants.BinFolder, assemblyName)); - References = References.Union(FileSystem.FileExists(assemblyPath) ? new[] { assemblyPath } : new[] { assemblyName }); + AddReference(FileSystem.FileExists(assemblyPath) ? assemblyPath : assemblyName); return new ScriptResult(); } @@ -87,10 +87,7 @@ public override ScriptResult Execute(string script) } catch (FileNotFoundException fileEx) { - if (References != null && References.Any(i => i == fileEx.FileName)) - { - References = References.Except(new[] {fileEx.FileName}); - } + RemoveReference(fileEx.FileName); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + fileEx + "\r\n"); return new ScriptResult { CompileException = fileEx }; diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 46e02aa1..41063b97 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; using Common.Logging; @@ -15,20 +17,90 @@ public class ScriptExecutor : IScriptExecutor public IFilePreProcessor FilePreProcessor { get; private set; } public IScriptEngine ScriptEngine { get; private set; } public ILog Logger { get; private set; } - public IEnumerable References { get; protected set; } + public Collection References { get; private set; } + public Collection Namespaces { get; private set; } public ScriptPackSession ScriptPackSession { get; protected set; } public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) { + References = new Collection(); + AddReferences(DefaultReferences); + Namespaces = new Collection(); + AddNamespaces(DefaultNamespaces); FileSystem = fileSystem; FilePreProcessor = filePreProcessor; ScriptEngine = scriptEngine; Logger = logger; } + public void AddNamespaces(IEnumerable namespaces) + { + Guard.AgainstNullArgument("namespaces", namespaces); + + foreach(var @namespace in namespaces) + { + AddNamespace(@namespace); + } + } + + public void AddNamespace(string @namespace) + { + Guard.AgainstNullArgument("namespace", @namespace); + + Namespaces.Add(@namespace); + } + + public void AddNamespaceByType(Type typeFromReferencedAssembly) + { + Guard.AgainstNullArgument("typeFromReferencedAssembly", typeFromReferencedAssembly); + + AddNamespace(typeFromReferencedAssembly.Namespace); + } + + public void AddNamespaceByType() + { + AddNamespaceByType(typeof(T)); + } + + public void AddReferences(IEnumerable paths) + { + Guard.AgainstNullArgument("paths", paths); + + foreach(var path in paths) + { + AddReference(path); + } + } + + public void AddReferenceByType(Type typeFromReferencedAssembly) + { + Guard.AgainstNullArgument("typeFromReferencedAssembly", typeFromReferencedAssembly); + + AddReference(typeFromReferencedAssembly.Assembly.Location); + } + + public void AddReferenceByType() + { + AddReferenceByType(typeof(T)); + } + + public void AddReference(string path) + { + Guard.AgainstNullArgument("path", path); + + References.Add(path); + } + + public void RemoveReference(string path) + { + Guard.AgainstNullArgument("path", path); + + References.Remove(path); + } + public virtual void Initialize(IEnumerable paths, IEnumerable scriptPacks) { - References = DefaultReferences.Union(paths); + AddReferences(paths); var bin = Path.Combine(FileSystem.CurrentDirectory, "bin"); ScriptEngine.BaseDirectory = bin; @@ -56,9 +128,10 @@ public virtual ScriptResult Execute(string script, string[] scriptArgs) var path = Path.IsPathRooted(script) ? script : Path.Combine(FileSystem.CurrentDirectory, script); var result = FilePreProcessor.ProcessFile(path); var references = References.Union(result.References); + var namespaces = Namespaces.Union(result.UsingStatements); Logger.Debug("Starting execution in engine"); - return ScriptEngine.Execute(result.Code, scriptArgs, references, DefaultNamespaces, ScriptPackSession); + return ScriptEngine.Execute(result.Code, scriptArgs, references, namespaces, ScriptPackSession); } } } \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index a9eecca7..b5b7d9df 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -219,14 +219,53 @@ public void ShouldAddReferenceToEachDestinationFile() var destPaths = new string[] { "System", "System.Core", destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; - scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); + scriptExecutor.AddReference("a"); + scriptExecutor.AddReferences(new[]{"b", "c", "d"}); + scriptExecutor.AddReferenceByType(); + scriptExecutor.AddReferenceByType(typeof(TheInitializeMethod)); + var explicitReferences = new[] { "a", "b", "c", "d", typeof(FactAttribute).Assembly.Location, typeof(TheInitializeMethod).Assembly.Location }; // act - scriptExecutor.Initialize(paths, Enumerable.Empty()); + scriptExecutor.Initialize(destPaths, Enumerable.Empty()); scriptExecutor.Execute(scriptName); // assert - scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(explicitReferences.Union(destPaths)))), It.IsAny>(), It.IsAny()), Times.Once()); + } + + [Fact] + public void ShouldAddNamespaces() + { + // arrange + var defaultReferences = ScriptExecutor.DefaultReferences; + var fileSystem = new Mock(); + var scriptEngine = new Mock(); + var preProcessor = new Mock(); + preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); + + var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); + + var currentDirectory = @"C:\"; + + var scriptName = "script.csx"; + + fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); + + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); + + scriptExecutor.AddNamespace("a"); + scriptExecutor.AddNamespaces(new[] { "b", "c", "d" }); + scriptExecutor.AddNamespaceByType(); + scriptExecutor.AddNamespaceByType(typeof(TheInitializeMethod)); + var explicitNamespaces = new[] { "a", "b", "c", "d", typeof(FactAttribute).Namespace, typeof(TheInitializeMethod).Namespace }; + // act + scriptExecutor.Initialize(new string[0], Enumerable.Empty()); + scriptExecutor.Execute(scriptName); + + // assert + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.Is>(x=>x.SequenceEqual(ScriptExecutor.DefaultNamespaces.Union(explicitNamespaces))), It.IsAny()), Times.Once()); } [Fact] @@ -274,4 +313,4 @@ public void ExecutorShouldPassDefaultReferencesToEngine() } } } -} \ No newline at end of file +} From bb4f4d13d32722969b047c8cd23aca02b903eaa2 Mon Sep 17 00:00:00 2001 From: lbargaoanu Date: Tue, 23 Jul 2013 14:53:53 +0300 Subject: [PATCH 0357/1224] ScriptExecutor tests refactoring --- .../ScriptCs.Core.Tests.csproj | 22 ++- .../ScriptExecutorTests.cs | 138 +++++------------- test/ScriptCs.Core.Tests/app.config | 19 +++ test/ScriptCs.Core.Tests/packages.config | 6 +- 4 files changed, 78 insertions(+), 107 deletions(-) create mode 100644 test/ScriptCs.Core.Tests/app.config diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 4052b23c..24cc0d24 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -26,9 +26,19 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + + ..\..\packages\AutoFixture.3.6.5\lib\net40\Ploeh.AutoFixture.dll + + + ..\..\packages\AutoFixture.AutoMoq.3.6.5\lib\net40\Ploeh.AutoFixture.AutoMoq.dll + + + ..\..\packages\AutoFixture.Xunit.3.6.5\lib\net40\Ploeh.AutoFixture.Xunit.dll + - - ..\..\packages\Should.1.1.12.0\lib\Should.dll + + False + ..\..\packages\Should.1.1.20\lib\Should.dll @@ -36,6 +46,10 @@ ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + False + ..\..\packages\xunit.extensions.1.9.1\lib\net20\xunit.extensions.dll + @@ -44,6 +58,9 @@ Properties\CommonVersionInfo.cs + + ScriptCsAutoDataAttribute.cs + @@ -68,6 +85,7 @@ + diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index b5b7d9df..45bd5ee5 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -2,49 +2,24 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Common.Logging; using Moq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Contracts; using Should; using Xunit; +using Xunit.Extensions; namespace ScriptCs.Tests { public class ScriptExecutorTests { - public static ScriptExecutor CreateScriptExecutor( - Mock fileSystem = null, - Mock fileProcessor = null, - Mock scriptEngine = null) - { - if (fileSystem == null) - { - fileSystem = new Mock(); - fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(@"C:\"); - } - - fileProcessor = fileProcessor ?? new Mock(); - - if (scriptEngine == null) - { - scriptEngine = new Mock(); - scriptEngine.SetupProperty(e => e.BaseDirectory); - } - - var logger = new Mock(); - - return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, logger.Object); - } - public class TheInitializeMethod { - [Fact] - public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() + [Theory, ScriptCsAutoData] + public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder([Frozen] Mock scriptEngine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor scriptExecutor) { // arrange - var scriptEngine = new Mock(); - var fileSystem = new Mock(); - var preProcessor = new Mock(); preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); var currentDirectory = @"C:\"; @@ -53,8 +28,6 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() scriptEngine.SetupProperty(e => e.BaseDirectory); - var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); - var paths = new string[0]; IEnumerable recipes = Enumerable.Empty(); @@ -66,24 +39,20 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() expectedBaseDirectory.ShouldEqual(scriptEngine.Object.BaseDirectory); } - [Fact] - public void ShouldInitializeScriptPacks() + [Theory, ScriptCsAutoData] + public void ShouldInitializeScriptPacks([Frozen] Mock preProcessor, [Frozen] Mock fileSystem, + [Frozen] Mock scriptPack1, ScriptExecutor scriptExecutor) { - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); // act - executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + scriptExecutor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); // assert scriptPack1.Verify(p => p.Initialize(It.IsAny())); @@ -92,19 +61,15 @@ public void ShouldInitializeScriptPacks() public class TheTerminateMethod { - [Fact] - public void ShouldTerminateScriptPacksWhenTerminateIsCalled() + [Theory, ScriptCsAutoData] + public void ShouldTerminateScriptPacksWhenTerminateIsCalled([Frozen] Mock preProcessor, [Frozen] Mock fileSystem, + [Frozen] Mock scriptPack1, ScriptExecutor executor) { - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); scriptPack1.Setup(p => p.Terminate()); @@ -121,59 +86,43 @@ public void ShouldTerminateScriptPacksWhenTerminateIsCalled() public class TheExecuteMethod { - [Fact] - public void ConstructsAbsolutePathBeforePreProcessingFile() + [Theory, ScriptCsAutoData] + public void ConstructsAbsolutePathBeforePreProcessingFile([Frozen] Mock preProcessor, [Frozen] Mock fileSystem, ScriptExecutor executor) { - var fileSystem = new Mock(); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); executor.Execute("script.csx"); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } - [Fact] - public void DoNotChangePathIfAbsolute() + [Theory, ScriptCsAutoData] + public void DoNotChangePathIfAbsolute([Frozen] Mock preProcessor, [Frozen] Mock fileSystem, ScriptExecutor executor) { - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); executor.Execute("script.csx"); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } - [Fact] - public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked() + [Theory, ScriptCsAutoData] + public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked([Frozen] Mock scriptEngine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor scriptExecutor) { - // arrange - var scriptEngine = new Mock(); - var preProcessor = new Mock(); - var fileSystem = new Mock(); - string code = Guid.NewGuid().ToString(); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - var scriptExecutor = CreateScriptExecutor( - fileSystem: fileSystem, - fileProcessor: preProcessor, - scriptEngine: scriptEngine); - var scriptName = "script.csx"; var paths = new string[0]; var recipes = Enumerable.Empty(); @@ -189,21 +138,16 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); scriptEngine.Verify(s => s.Execute(code, It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); - } - [Fact] - public void ShouldAddReferenceToEachDestinationFile() + [Theory, ScriptCsAutoData] + public void ShouldAddReferenceToEachDestinationFile([Frozen] Mock scriptEngine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor scriptExecutor) { // arrange var defaultReferences = ScriptExecutor.DefaultReferences; - var fileSystem = new Mock(); - var scriptEngine = new Mock(); - var preProcessor = new Mock(); preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); - var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); - var currentDirectory = @"C:\"; var destinationFilePath1 = Path.Combine(currentDirectory, @"bin\fileName1.cs"); var destinationFilePath2 = Path.Combine(currentDirectory, @"bin\fileName2.cs"); @@ -222,7 +166,7 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); scriptExecutor.AddReference("a"); - scriptExecutor.AddReferences(new[]{"b", "c", "d"}); + scriptExecutor.AddReferences(new[]{"a", "a", "b", "c", "d"}); scriptExecutor.AddReferenceByType(); scriptExecutor.AddReferenceByType(typeof(TheInitializeMethod)); var explicitReferences = new[] { "a", "b", "c", "d", typeof(FactAttribute).Assembly.Location, typeof(TheInitializeMethod).Assembly.Location }; @@ -234,18 +178,14 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(explicitReferences.Union(destPaths)))), It.IsAny>(), It.IsAny()), Times.Once()); } - [Fact] - public void ShouldAddNamespaces() + [Theory, ScriptCsAutoData] + public void ShouldAddNamespaces([Frozen] Mock scriptEngine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor scriptExecutor) { // arrange var defaultReferences = ScriptExecutor.DefaultReferences; - var fileSystem = new Mock(); - var scriptEngine = new Mock(); - var preProcessor = new Mock(); preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); - var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); - var currentDirectory = @"C:\"; var scriptName = "script.csx"; @@ -256,7 +196,7 @@ public void ShouldAddNamespaces() scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); scriptExecutor.AddNamespace("a"); - scriptExecutor.AddNamespaces(new[] { "b", "c", "d" }); + scriptExecutor.AddNamespaces(new[] {"a", "a", "b", "c", "d" }); scriptExecutor.AddNamespaceByType(); scriptExecutor.AddNamespaceByType(typeof(TheInitializeMethod)); var explicitNamespaces = new[] { "a", "b", "c", "d", typeof(FactAttribute).Namespace, typeof(TheInitializeMethod).Namespace }; @@ -268,44 +208,34 @@ public void ShouldAddNamespaces() scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.Is>(x=>x.SequenceEqual(ScriptExecutor.DefaultNamespaces.Union(explicitNamespaces))), It.IsAny()), Times.Once()); } - [Fact] - public void ExecutorShouldPassDefaultNamespacesToEngine() + [Theory, ScriptCsAutoData] + public void ExecutorShouldPassDefaultNamespacesToEngine([Frozen] Mock engine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor executor) { var expectedNamespaces = ScriptExecutor.DefaultNamespaces; - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var engine = new Mock(); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); executor.Execute("script.csx"); engine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); } - [Fact] - public void ExecutorShouldPassDefaultReferencesToEngine() + [Theory, ScriptCsAutoData] + public void ExecutorShouldPassDefaultReferencesToEngine([Frozen] Mock engine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor executor) { var defaultReferences = ScriptExecutor.DefaultReferences; - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var engine = new Mock(); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); executor.Execute("script.csx"); @@ -313,4 +243,4 @@ public void ExecutorShouldPassDefaultReferencesToEngine() } } } -} +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/app.config b/test/ScriptCs.Core.Tests/app.config new file mode 100644 index 00000000..280e1ca4 --- /dev/null +++ b/test/ScriptCs.Core.Tests/app.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/packages.config b/test/ScriptCs.Core.Tests/packages.config index 2fc851e7..d7496cbb 100644 --- a/test/ScriptCs.Core.Tests/packages.config +++ b/test/ScriptCs.Core.Tests/packages.config @@ -1,9 +1,13 @@  + + + - + + \ No newline at end of file From cbb5e1be059f77613044be30af696fbab7b94c27 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 24 Jul 2013 13:44:24 -0700 Subject: [PATCH 0358/1224] Refactored runtime into a ScriptContainerFactory, this will enable reuse of the initialization container for loading modules. Also added module loader infra but not wired up yet --- .../FilePreProcessorResult.cs | 22 ++ src/ScriptCs.Contracts/IAssemblyResolver.cs | 9 + src/ScriptCs.Contracts/IAssemblyUtility.cs | 7 + src/ScriptCs.Contracts/IFilePreProcessor.cs | 11 + .../IFilePreProcessorResult.cs | 16 + src/ScriptCs.Contracts/IFileSystem.cs | 47 +++ .../IPackageAssemblyResolver.cs | 13 + src/ScriptCs.Contracts/IScriptCsModule.cs | 14 + src/ScriptCs.Contracts/IScriptEngine.cs | 10 + src/ScriptCs.Contracts/IScriptExecutor.cs | 13 + src/ScriptCs.Contracts/IScriptHostFactory.cs | 11 + src/ScriptCs.Contracts/IScriptPackManager.cs | 9 + src/ScriptCs.Contracts/IScriptPackResolver.cs | 10 + src/ScriptCs.Contracts/IScriptResult.cs | 19 ++ src/ScriptCs.Contracts/IScriptRuntime.cs | 12 + .../IScriptRuntimeBuilder.cs | 31 ++ src/ScriptCs.Contracts/LogLevel.cs | 10 + src/ScriptCs.Core/IScriptContainerFactory.cs | 10 + src/ScriptCs.Core/ScriptContainerFactory.cs | 143 +++++++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 2 + src/ScriptCs.Core/ScriptRuntime.cs | 139 +------- src/ScriptCs.Hosting/IModule.cs | 13 + src/ScriptCs.Hosting/IModuleMetadata.cs | 8 + src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs | 26 ++ src/ScriptCs.Hosting/ModuleAttribute.cs | 15 + src/ScriptCs.Hosting/ModuleLoader.cs | 54 ++++ src/ScriptCs.Hosting/ScriptCs.Hosting.csproj | 6 + src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs | 39 +-- src/ScriptCs/ModuleAttribute.cs | 14 + src/ScriptCs/Program.cs | 17 +- src/ScriptCs/ScriptCs.csproj | 1 + .../ScriptContainerFactoryTests.cs | 235 ++++++++++++++ .../ScriptCs.Core.Tests.csproj | 1 + .../ScriptCs.Core.Tests/ScriptRuntimeTests.cs | 300 +----------------- 34 files changed, 845 insertions(+), 442 deletions(-) create mode 100644 src/ScriptCs.Contracts/FilePreProcessorResult.cs create mode 100644 src/ScriptCs.Contracts/IAssemblyResolver.cs create mode 100644 src/ScriptCs.Contracts/IAssemblyUtility.cs create mode 100644 src/ScriptCs.Contracts/IFilePreProcessor.cs create mode 100644 src/ScriptCs.Contracts/IFilePreProcessorResult.cs create mode 100644 src/ScriptCs.Contracts/IFileSystem.cs create mode 100644 src/ScriptCs.Contracts/IPackageAssemblyResolver.cs create mode 100644 src/ScriptCs.Contracts/IScriptCsModule.cs create mode 100644 src/ScriptCs.Contracts/IScriptEngine.cs create mode 100644 src/ScriptCs.Contracts/IScriptExecutor.cs create mode 100644 src/ScriptCs.Contracts/IScriptHostFactory.cs create mode 100644 src/ScriptCs.Contracts/IScriptPackManager.cs create mode 100644 src/ScriptCs.Contracts/IScriptPackResolver.cs create mode 100644 src/ScriptCs.Contracts/IScriptResult.cs create mode 100644 src/ScriptCs.Contracts/IScriptRuntime.cs create mode 100644 src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs create mode 100644 src/ScriptCs.Contracts/LogLevel.cs create mode 100644 src/ScriptCs.Core/IScriptContainerFactory.cs create mode 100644 src/ScriptCs.Core/ScriptContainerFactory.cs create mode 100644 src/ScriptCs.Hosting/IModule.cs create mode 100644 src/ScriptCs.Hosting/IModuleMetadata.cs create mode 100644 src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs create mode 100644 src/ScriptCs.Hosting/ModuleAttribute.cs create mode 100644 src/ScriptCs.Hosting/ModuleLoader.cs create mode 100644 src/ScriptCs/ModuleAttribute.cs create mode 100644 test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs diff --git a/src/ScriptCs.Contracts/FilePreProcessorResult.cs b/src/ScriptCs.Contracts/FilePreProcessorResult.cs new file mode 100644 index 00000000..f5731ebe --- /dev/null +++ b/src/ScriptCs.Contracts/FilePreProcessorResult.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public class FilePreProcessorResult + { + public FilePreProcessorResult() + { + UsingStatements = new List(); + LoadedScripts = new List(); + References = new List(); + } + + public List UsingStatements { get; set; } + + public List LoadedScripts { get; set; } + + public List References { get; set; } + + public string Code { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IAssemblyResolver.cs b/src/ScriptCs.Contracts/IAssemblyResolver.cs new file mode 100644 index 00000000..04bc3338 --- /dev/null +++ b/src/ScriptCs.Contracts/IAssemblyResolver.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public interface IAssemblyResolver + { + IEnumerable GetAssemblyPaths(string path); + } +} diff --git a/src/ScriptCs.Contracts/IAssemblyUtility.cs b/src/ScriptCs.Contracts/IAssemblyUtility.cs new file mode 100644 index 00000000..805b4d5b --- /dev/null +++ b/src/ScriptCs.Contracts/IAssemblyUtility.cs @@ -0,0 +1,7 @@ +namespace ScriptCs +{ + public interface IAssemblyUtility + { + bool IsManagedAssembly(string assemblyPath); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IFilePreProcessor.cs b/src/ScriptCs.Contracts/IFilePreProcessor.cs new file mode 100644 index 00000000..d4943eb2 --- /dev/null +++ b/src/ScriptCs.Contracts/IFilePreProcessor.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace ScriptCs.Contracts +{ + public interface IFilePreProcessor + { + FilePreProcessorResult ProcessFile(string path); + + FilePreProcessorResult ProcessScript(string script); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IFilePreProcessorResult.cs b/src/ScriptCs.Contracts/IFilePreProcessorResult.cs new file mode 100644 index 00000000..780d7559 --- /dev/null +++ b/src/ScriptCs.Contracts/IFilePreProcessorResult.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs.Contracts +{ + public interface IFilePreProcessorResult + { + List UsingStatements { get; set; } + List LoadedScripts { get; set; } + List References { get; set; } + string Code { get; set; } + } +} diff --git a/src/ScriptCs.Contracts/IFileSystem.cs b/src/ScriptCs.Contracts/IFileSystem.cs new file mode 100644 index 00000000..f4c152ee --- /dev/null +++ b/src/ScriptCs.Contracts/IFileSystem.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace ScriptCs.Contracts +{ + public interface IFileSystem + { + IEnumerable EnumerateFiles(string dir, string search, SearchOption searchOption = SearchOption.AllDirectories); + + void Copy(string source, string dest, bool overwrite); + + bool DirectoryExists(string path); + + void CreateDirectory(string path); + + void DeleteDirectory(string path); + + string ReadFile(string path); + + string[] ReadFileLines(string path); + + DateTime GetLastWriteTime(string file); + + bool IsPathRooted(string path); + + string GetFullPath(string path); + + string CurrentDirectory { get; } + + string NewLine { get; } + + string GetWorkingDirectory(string path); + + void Move(string source, string dest); + + bool FileExists(string path); + + void FileDelete(string path); + + IEnumerable SplitLines(string value); + + void WriteToFile(string path, string text); + + Stream CreateFileStream(string filePath, FileMode mode); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs b/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs new file mode 100644 index 00000000..62fb4d83 --- /dev/null +++ b/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using ScriptCs.Package; + +namespace ScriptCs.Contracts +{ + public interface IPackageAssemblyResolver + { + void SavePackages(Action output); + IEnumerable GetPackages(string workingDirectory); + IEnumerable GetAssemblyNames(string workingDirectory, Action outputCallback = null); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptCsModule.cs b/src/ScriptCs.Contracts/IScriptCsModule.cs new file mode 100644 index 00000000..3e6855e2 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptCsModule.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs.Contracts +{ + public interface IScriptCsModule + { + void Initialize(IScriptRuntimeBuilder builder); + } +} diff --git a/src/ScriptCs.Contracts/IScriptEngine.cs b/src/ScriptCs.Contracts/IScriptEngine.cs new file mode 100644 index 00000000..b4081283 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptEngine.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace ScriptCs.Contracts +{ + public interface IScriptEngine + { + string BaseDirectory { get; set; } + IScriptResult Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptExecutor.cs b/src/ScriptCs.Contracts/IScriptExecutor.cs new file mode 100644 index 00000000..8b2c531f --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptExecutor.cs @@ -0,0 +1,13 @@ +using ScriptCs.Contracts; +using System.Collections.Generic; + +namespace ScriptCs.Contracts +{ + public interface IScriptExecutor + { + void Initialize(IEnumerable paths, IEnumerable scriptPacks); + ScriptResult Execute(string script, string[] scriptArgs); + ScriptResult Execute(string script); + void Terminate(); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptHostFactory.cs b/src/ScriptCs.Contracts/IScriptHostFactory.cs new file mode 100644 index 00000000..153ca62c --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptHostFactory.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +using ScriptCs.Contracts; + +namespace ScriptCs.Contracts +{ + public interface IScriptHostFactory + { + ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs); + } +} diff --git a/src/ScriptCs.Contracts/IScriptPackManager.cs b/src/ScriptCs.Contracts/IScriptPackManager.cs new file mode 100644 index 00000000..2a51a49e --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptPackManager.cs @@ -0,0 +1,9 @@ +using ScriptCs.Contracts; + +namespace ScriptCs.Contracts +{ + public interface IScriptPackManager + { + TContext Get() where TContext : IScriptPackContext; + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptPackResolver.cs b/src/ScriptCs.Contracts/IScriptPackResolver.cs new file mode 100644 index 00000000..cf728f0e --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptPackResolver.cs @@ -0,0 +1,10 @@ +using ScriptCs.Contracts; +using System.Collections.Generic; + +namespace ScriptCs.Contracts +{ + public interface IScriptPackResolver + { + IEnumerable GetPacks(); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptResult.cs b/src/ScriptCs.Contracts/IScriptResult.cs new file mode 100644 index 00000000..e7b28885 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptResult.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs.Contracts +{ + public interface IScriptResult + { + object ReturnValue { get; set; } + Exception ExecuteException { get; set; } + Exception CompileException { get; set; } + bool ContinueBuffering { get; set; } + bool IsPendingClosingChar { get; set; } + char? ExpectingClosingChar { get; set; } + void UpdateClosingExpectation(Exception ex); + } +} diff --git a/src/ScriptCs.Contracts/IScriptRuntime.cs b/src/ScriptCs.Contracts/IScriptRuntime.cs new file mode 100644 index 00000000..6717fa06 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptRuntime.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs.Contracts +{ + class IScriptRuntime + { + } +} diff --git a/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs b/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs new file mode 100644 index 00000000..d89bfaef --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs.Contracts +{ + public interface IScriptRuntimeBuilder + { + ScriptRuntime Build(); + IScriptRuntimeBuilder Debug(bool debug = true); + IScriptRuntimeBuilder ScriptName(string name); + IScriptRuntimeBuilder Repl(bool repl = true); + IScriptRuntimeBuilder LogLevel(LogLevel level); + IScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor; + IScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine; + IScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory; + IScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager; + IScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver; + IScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider; + IScriptRuntimeBuilder FileSystem() where T : IFileSystem; + IScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility; + IScriptRuntimeBuilder PackageContainer() where T : IPackageContainer; + IScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor; + IScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver; + IScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor; + } +} diff --git a/src/ScriptCs.Contracts/LogLevel.cs b/src/ScriptCs.Contracts/LogLevel.cs new file mode 100644 index 00000000..bd15dd0e --- /dev/null +++ b/src/ScriptCs.Contracts/LogLevel.cs @@ -0,0 +1,10 @@ +namespace ScriptCs.Contracts +{ + public enum LogLevel + { + Error, + Info, + Debug, + Trace + } +} diff --git a/src/ScriptCs.Core/IScriptContainerFactory.cs b/src/ScriptCs.Core/IScriptContainerFactory.cs new file mode 100644 index 00000000..a9420f34 --- /dev/null +++ b/src/ScriptCs.Core/IScriptContainerFactory.cs @@ -0,0 +1,10 @@ +using Autofac; + +namespace ScriptCs +{ + public interface IScriptContainerFactory + { + IContainer InitializationContainer { get; } + IContainer RuntimeContainer { get; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptContainerFactory.cs b/src/ScriptCs.Core/ScriptContainerFactory.cs new file mode 100644 index 00000000..f232787b --- /dev/null +++ b/src/ScriptCs.Core/ScriptContainerFactory.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Autofac.Core; +using Autofac.Integration.Mef; +using Common.Logging; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs +{ + public class ScriptContainerFactory : IScriptContainerFactory + { + private readonly ILog _logger; + private readonly IConsole _console; + private readonly Type _scriptEngineType; + private readonly Type _scriptExecutorType; + private readonly bool _initDirectoryCatalog; + private IDictionary _overrides = null; + + public ScriptContainerFactory(ILog logger, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IDictionary overrides ) + { + Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); + Guard.AgainstNullArgument("scriptEngine", scriptEngineType); + Guard.AgainstNullArgument("console", console); + Guard.AgainstNullArgument("logger", logger); + + if (overrides == null) + overrides = new Dictionary(); + + _logger = logger; + _console = console; + _scriptEngineType = scriptEngineType; + _scriptExecutorType = scriptExecutorType; + _initDirectoryCatalog = initDirectoryCatalog; + _overrides = overrides; + } + + private IContainer _initializationContainer; + public IContainer InitializationContainer + { + get + { + if (_initializationContainer == null) + { + _initializationContainer = CreateInitializationContainer(); + } + return _initializationContainer; + } + } + + private IContainer _runtimeContainer; + public IContainer RuntimeContainer + { + get + { + if (_runtimeContainer == null) + { + _runtimeContainer = CreateRuntimeContainer(); + } + return _runtimeContainer; + } + } + + private IContainer CreateInitializationContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(_logger); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + return builder.Build(); + } + + private IContainer CreateRuntimeContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(_logger).Exported(x => x.As()); + builder.RegisterType(_scriptEngineType).As(); + builder.RegisterType(_scriptExecutorType).As(); + builder.RegisterInstance(_console).As(); + builder.RegisterType(); + + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType()); + + var initializationContainer = InitializationContainer; + var assemblyResolver = initializationContainer.Resolve(); + + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(assemblyResolver).As(); + + if (_initDirectoryCatalog) + { + var currentDirectory = Environment.CurrentDirectory; + var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); + + var aggregateCatalog = new AggregateCatalog(); + + assemblies.Select(x => new AssemblyCatalog(x)).ToList() + .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); + + builder.RegisterComposablePartCatalog(aggregateCatalog); + } + + return builder.Build(); + } + + private void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) + { + if (_overrides.ContainsKey(typeof(T))) + { + var reg = _overrides[typeof(T)]; + if (reg.GetType().IsSubclassOf(typeof(Type))) + { + builder.RegisterType((Type)reg).As().SingleInstance(); + } + else + { + builder.RegisterInstance(reg).As(); + } + } + else + { + registrationAction(builder); + } + } + } +} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 361d92e7..9a93ff5c 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -44,6 +44,8 @@ + + diff --git a/src/ScriptCs.Core/ScriptRuntime.cs b/src/ScriptCs.Core/ScriptRuntime.cs index a88191c2..ea8182f6 100644 --- a/src/ScriptCs.Core/ScriptRuntime.cs +++ b/src/ScriptCs.Core/ScriptRuntime.cs @@ -15,143 +15,22 @@ namespace ScriptCs { public class ScriptRuntime { - private readonly bool _shouldInitDirectoryCatalog; - private IContainer _container; - private ScriptServices _scriptServices; - private IDictionary _overrides; - private Type _scriptExecutorType; - private Type _scriptEngineType; - private IConsole _console; - private string _scriptName; - private bool _repl; - private ILoggerConfigurator _loggerConfigurator; - - public ScriptRuntime(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType) - : this(scriptName, repl, loggerConfigurator, console, scriptExecutorType, scriptEngineType, new Dictionary()) - { - } - - public ScriptRuntime(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) + public ScriptRuntime(ILog logger, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IDictionary overrides) + : this(new ScriptContainerFactory(logger, console, scriptEngineType, scriptExecutorType, initDirectoryCatalog, overrides)) { - Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); - Guard.AgainstNullArgument("scriptEngine", scriptEngineType); - Guard.AgainstNullArgument("console", console); - Guard.AgainstNullArgument("loggerConfigurator", loggerConfigurator); - - _loggerConfigurator = loggerConfigurator; - _console = console; - _scriptName = scriptName; - _repl = repl; - - if (!typeof(IScriptExecutor).IsAssignableFrom(scriptExecutorType)) - { - throw new ArgumentException("scriptExecutor type must implement IScriptExecutor", "scriptExecutor"); - } - - if (!typeof(IScriptEngine).IsAssignableFrom(scriptEngineType)) - { - throw new ArgumentException("scriptEngine type must implement IScriptEngine", "scriptEngine"); - } - - _scriptExecutorType = scriptExecutorType; - _scriptEngineType = scriptEngineType; - - _overrides = overrides; - _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(_repl, _scriptName); + } - public void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) + public ScriptRuntime(IScriptContainerFactory containerFactory) { - if (_overrides.ContainsKey(typeof(T))) - { - var reg = _overrides[typeof(T)]; - if (reg.GetType().IsSubclassOf(typeof(Type))) - { - builder.RegisterType((Type)reg).As().SingleInstance(); - } - else - { - builder.RegisterInstance(reg).As(); - } - } - else - { - registrationAction(builder); - } + var container = containerFactory.RuntimeContainer; + ScriptServices = container.Resolve(); + Logger = container.Resolve(); } - public IContainer Initialize() - { - var builder = new ContainerBuilder(); - - _loggerConfigurator.Configure(_console); - var logger = _loggerConfigurator.GetLogger(); - - builder.RegisterInstance(logger).Exported(x => x.As()); - builder.RegisterType(_scriptEngineType).As(); - builder.RegisterType(_scriptExecutorType).As(); - builder.RegisterInstance(_console).As(); - builder.RegisterType(); - - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType()); - - // Hack using a second container to resolve assemblies for MEF catalog before building Autofac container - var tempBuilder = new ContainerBuilder(); - - tempBuilder.RegisterInstance(logger); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - - var tempContainer = tempBuilder.Build(); - var assemblyResolver = tempContainer.Resolve(); - - builder.RegisterInstance(tempContainer.Resolve()).As(); - builder.RegisterInstance(tempContainer.Resolve()).As(); - builder.RegisterInstance(tempContainer.Resolve()).As(); - builder.RegisterInstance(tempContainer.Resolve()).As(); - builder.RegisterInstance(assemblyResolver).As(); + public ScriptServices ScriptServices { get; private set; } - if (_shouldInitDirectoryCatalog) - { - var currentDirectory = Environment.CurrentDirectory; - var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); - - var aggregateCatalog = new AggregateCatalog(); - - assemblies.Select(x => new AssemblyCatalog(x)).ToList() - .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); - - builder.RegisterComposablePartCatalog(aggregateCatalog); - } - - _container = builder.Build(); - - _scriptServices = _container.Resolve(); - return _container; - } - - public ScriptServices GetScriptServices() - { - return _scriptServices; - } - - public ILog GetLogger() - { - return _container.Resolve(); - } - - private static bool ShouldInitDirectoryCatalog(bool repl, string scriptName) - { - return repl || !string.IsNullOrWhiteSpace(scriptName); - } + public ILog Logger { get; private set; } } } diff --git a/src/ScriptCs.Hosting/IModule.cs b/src/ScriptCs.Hosting/IModule.cs new file mode 100644 index 00000000..f1c70eed --- /dev/null +++ b/src/ScriptCs.Hosting/IModule.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs +{ + public interface IModule + { + void Initialize(IScriptRuntimeBuilder builder, bool repl, bool debug); + } +} diff --git a/src/ScriptCs.Hosting/IModuleMetadata.cs b/src/ScriptCs.Hosting/IModuleMetadata.cs new file mode 100644 index 00000000..74f09ea2 --- /dev/null +++ b/src/ScriptCs.Hosting/IModuleMetadata.cs @@ -0,0 +1,8 @@ +namespace ScriptCs +{ + public interface IModuleMetadata + { + string Name { get; } + string Extensions { get; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs b/src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs new file mode 100644 index 00000000..bbc82d30 --- /dev/null +++ b/src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs @@ -0,0 +1,26 @@ +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs +{ + public interface IScriptRuntimeBuilder + { + ScriptRuntime Build(); + IScriptRuntimeBuilder Debug(bool debug = true); + IScriptRuntimeBuilder ScriptName(string name); + IScriptRuntimeBuilder Repl(bool repl = true); + IScriptRuntimeBuilder LogLevel(LogLevel level); + IScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor; + IScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine; + IScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory; + IScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager; + IScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver; + IScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider; + IScriptRuntimeBuilder FileSystem() where T : IFileSystem; + IScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility; + IScriptRuntimeBuilder PackageContainer() where T : IPackageContainer; + IScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor; + IScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver; + IScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor; + } +} \ No newline at end of file diff --git a/src/ScriptCs.Hosting/ModuleAttribute.cs b/src/ScriptCs.Hosting/ModuleAttribute.cs new file mode 100644 index 00000000..6f438db0 --- /dev/null +++ b/src/ScriptCs.Hosting/ModuleAttribute.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.Composition; + +namespace ScriptCs.Hosting +{ + public class ModuleAttribute : ExportAttribute, IModuleMetadata + { + public ModuleAttribute(string name) : base(typeof (IModule)) + { + Name = name; + } + + public string Name { get; private set; } + public string Extensions { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Hosting/ModuleLoader.cs b/src/ScriptCs.Hosting/ModuleLoader.cs new file mode 100644 index 00000000..92e81eef --- /dev/null +++ b/src/ScriptCs.Hosting/ModuleLoader.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs +{ + public class ModuleLoader + { + private readonly IAssemblyResolver _resolver; + private readonly Action _catalogAction; + + [ImportingConstructor] + public ModuleLoader(IAssemblyResolver resolver) : + this(resolver, null) + { + } + + public ModuleLoader(IAssemblyResolver resolver, Action catalogAction) + { + _resolver = resolver; + _catalogAction = catalogAction; + if (catalogAction == null) + catalogAction = (p, catalog) => catalog.Catalogs.Add(new AssemblyCatalog(p)); + + _catalogAction = catalogAction; + } + + public void Load(IScriptRuntimeBuilder builder, string modulePackagesPath, string extension, bool repl, bool debug, string[] moduleNames) + { + var paths = _resolver.GetAssemblyPaths(modulePackagesPath); + var catalog = new AggregateCatalog(); + foreach (var path in paths) + { + _catalogAction(path, catalog); + } + + var container = new CompositionContainer(catalog); + var modules = container.GetExports() + .Where(m => moduleNames.Contains(m.Metadata.Name) || + (extension != null && (m.Metadata.Extensions == extension || m.Metadata.Extensions.Split(',').Contains(extension)))) + .Select(m => m.Value); + + foreach (var module in modules) + { + module.Initialize(builder, repl, debug); + } + } + } +} diff --git a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index 7acdba64..179dd3c6 100644 --- a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -19,6 +19,7 @@ ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll + @@ -47,8 +48,13 @@ Properties\CommonVersionInfo.cs + + + + + diff --git a/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs index 89f4bf70..3cf69f23 100644 --- a/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs +++ b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs @@ -9,7 +9,7 @@ namespace ScriptCs { - public class ScriptRuntimeBuilder + public class ScriptRuntimeBuilder : IScriptRuntimeBuilder { private bool _debug = false; private bool _repl = false; @@ -39,102 +39,103 @@ public ScriptRuntime Build() } var loggerConfigurator = new LoggerConfigurator(_logLevel); - - var runtime = new ScriptRuntime(_scriptName, _repl, loggerConfigurator, new ScriptConsole(), _scriptExecutorType, _scriptEngineType, _overrides); + var initDirectoryCatalog = _scriptName.Length > 0 || _repl; + var factory = new ScriptContainerFactory(loggerConfigurator.GetLogger(), new ScriptConsole(), _scriptEngineType, _scriptExecutorType, initDirectoryCatalog, _overrides); + var runtime = new ScriptRuntime(factory); return runtime; } - public ScriptRuntimeBuilder Debug(bool debug = true) + public IScriptRuntimeBuilder Debug(bool debug = true) { _debug = debug; return this; } - public ScriptRuntimeBuilder ScriptName(string name) + public IScriptRuntimeBuilder ScriptName(string name) { _scriptName = name; return this; } - public ScriptRuntimeBuilder Repl(bool repl = true) + public IScriptRuntimeBuilder Repl(bool repl = true) { _repl = repl; return this; } - public ScriptRuntimeBuilder LogLevel(LogLevel level) + public IScriptRuntimeBuilder LogLevel(LogLevel level) { _logLevel = level; return this; } - public ScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor + public IScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor { _scriptExecutorType = typeof (T); return this; } - public ScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine + public IScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine { _scriptEngineType = typeof(T); return this; } - public ScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory + public IScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory { _overrides[typeof(IScriptHostFactory)] = typeof(T); return this; } - public ScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager + public IScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager { _overrides[typeof(IScriptPackManager)] = typeof(T); return this; } - public ScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver + public IScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver { _overrides[typeof(IScriptPackResolver)] = typeof(T); return this; } - public ScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider + public IScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider { _overrides[typeof(IInstallationProvider)] = typeof(T); return this; } - public ScriptRuntimeBuilder FileSystem() where T : IFileSystem + public IScriptRuntimeBuilder FileSystem() where T : IFileSystem { _overrides[typeof(IFileSystem)] = typeof(T); return this; } - public ScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility + public IScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility { _overrides[typeof(IAssemblyUtility)] = typeof(T); return this; } - public ScriptRuntimeBuilder PackageContainer() where T : IPackageContainer + public IScriptRuntimeBuilder PackageContainer() where T : IPackageContainer { _overrides[typeof(IPackageContainer)] = typeof(T); return this; } - public ScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor + public IScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor { _overrides[typeof(IFilePreProcessor)] = typeof(T); return this; } - public ScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver + public IScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver { _overrides[typeof(IPackageAssemblyResolver)] = typeof(T); return this; } - public ScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor + public IScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor { _overrides[typeof(IAssemblyResolver)] = typeof(T); return this; diff --git a/src/ScriptCs/ModuleAttribute.cs b/src/ScriptCs/ModuleAttribute.cs new file mode 100644 index 00000000..c02bb5ec --- /dev/null +++ b/src/ScriptCs/ModuleAttribute.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.Composition; + +namespace ScriptCs.Hosting +{ + public class ModuleAttribute : ExportAttribute + { + public ModuleAttribute(string name) : base(typeof (IModule)) + { + Name = name; + } + + public string Name { get; private set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index c635f873..5039329c 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,5 +1,5 @@ using System; - +using Autofac; using PowerArgs; using ScriptCs.Command; using System.Linq; @@ -16,19 +16,22 @@ private static int Main(string[] args) var commandArgs = ParseArguments(args); - var runtime = new ScriptRuntimeBuilder(). + var runtimeBuilder = new ScriptRuntimeBuilder(). Debug(commandArgs.Debug). LogLevel(commandArgs.LogLevel). ScriptName(commandArgs.ScriptName). - Repl(commandArgs.Repl). - Build(); + Repl(commandArgs.Repl); + + var containerBuilder = new ContainerBuilder(); + + - runtime.Initialize(); + var runtime = runtimeBuilder.Build(); - var logger = runtime.GetLogger(); + var logger = runtime.Logger; logger.Debug("Creating ScriptServices"); - var scriptServiceRoot = runtime.GetScriptServices(); + var scriptServiceRoot = runtime.ScriptServices; var commandFactory = new CommandFactory(scriptServiceRoot); var command = commandFactory.CreateCommand(commandArgs, scriptArgs); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index ac3e3e66..83d09dc3 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -73,6 +73,7 @@ + diff --git a/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs b/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs new file mode 100644 index 00000000..fd0c385d --- /dev/null +++ b/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Common.Logging; +using Moq; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class ScriptContainerFactoryTests + { + public class TheCreateInitializationContainerMethod + { + + } + + public class TheCreateRuntimeContainerMethod + { + private Mock _mockConsole = new Mock(); + private Type _scriptExecutorType = null; + private Type _scriptEngineType = null; + private Mock _mockLogger = new Mock(); + private IDictionary _overrides = new Dictionary(); + private IScriptContainerFactory _factory = null; + + public TheCreateRuntimeContainerMethod() + { + var mockScriptExecutorType = new Mock(); + _scriptExecutorType = mockScriptExecutorType.Object.GetType(); + + var mockScriptEngineType = new Mock(); + _scriptEngineType = mockScriptEngineType.Object.GetType(); + + _factory = new ScriptContainerFactory(_mockLogger.Object, _mockConsole.Object, _scriptEngineType, _scriptExecutorType, false, _overrides); + } + + [Fact] + public void ShouldRegisterTheLoggerInstance() + { + var logger = _factory.RuntimeContainer.Resolve(); + logger.ShouldEqual(_mockLogger.Object); + } + + [Fact] + public void ShouldRegisterTheScriptEngine() + { + var engine = _factory.RuntimeContainer.Resolve(); + engine.GetType().ShouldEqual(_scriptEngineType); + } + + [Fact] + public void ShouldRegisterTheExecutor() + { + var executor = _factory.RuntimeContainer.Resolve(); + executor.GetType().ShouldEqual(_scriptExecutorType); + } + + [Fact] + public void ShouldRegisterTheConsoleInstance() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheScriptServices() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultFileSystemIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheOverriddenScriptHostFactory() + { + var mock = new Mock(); + _overrides[typeof(IScriptHostFactory)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenFilePreProcessor() + { + var mock = new Mock(); + _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenScriptPackResolver() + { + var mock = new Mock(); + _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenInstallationProvider() + { + var mock = new Mock(); + _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageInstaller() + { + var mock = new Mock(); + _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenFileSystem() + { + var mock = new Mock(); + _overrides[typeof(IFileSystem)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyUtility() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageContainer() + { + var mock = new Mock(); + _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageAssemblyResolver() + { + var mock = new Mock(); + _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyResolver() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyResolverInstance() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyResolver)] = mock.Object; + _factory.RuntimeContainer.Resolve().ShouldEqual(mock.Object); + } + } + } +} diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 4052b23c..c4ecdce7 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -45,6 +45,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs index 61c20a5b..f5ede929 100644 --- a/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading.Tasks; using Autofac; +using Autofac.Core.Registration; using Common.Logging; using Moq; using ScriptCs.Contracts; @@ -18,307 +19,34 @@ public class ScriptRuntimeTests { public class TheInitializeMethod { - private Mock _mockConsole = new Mock(); - private Type _scriptExecutorType = null; - private Type _scriptEngineType = null; - private Mock _mockLoggerConfigurator = new Mock(); private Mock _mockLogger = new Mock(); - private IDictionary _overrides = new Dictionary(); + private ScriptServices _scriptServices = new ScriptServices(null, null, null, null,null,null,null,null,null,null); + private Mock _mockFactory = new Mock(); + private ScriptRuntime _runtime = null; public TheInitializeMethod() { - var mockScriptExecutorType = new Mock(); - _scriptExecutorType = mockScriptExecutorType.Object.GetType(); - - var mockScriptEngineType = new Mock(); - _scriptEngineType = mockScriptEngineType.Object.GetType(); - - _mockLoggerConfigurator.Setup(l => l.GetLogger()).Returns(_mockLogger.Object); - } - - [Fact] - public void ShouldInvokeTheConfigureMethod() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - runtime.Initialize(); - _mockLoggerConfigurator.Verify(l=>l.Configure(It.IsAny())); - - } - - [Fact] - public void ShouldGetTheLogger() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - runtime.Initialize(); - _mockLoggerConfigurator.Verify(l=>l.GetLogger()); - } - - [Fact] - public void ShouldRegisterTheLoggerInstance() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - var logger = container.Resolve(); - logger.ShouldEqual(_mockLogger.Object); - } - - [Fact] - public void ShouldRegisterTheScriptEngine() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - var engine = container.Resolve(); - engine.GetType().ShouldEqual(_scriptEngineType); - } - - [Fact] - public void ShouldRegisterTheExecutor() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - var executor = container.Resolve(); - executor.GetType().ShouldEqual(_scriptExecutorType); - } - - [Fact] - public void ShouldRegisterTheConsoleInstance() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); + var builder = new ContainerBuilder(); + builder.RegisterInstance(_mockLogger.Object); + builder.RegisterInstance(_scriptServices); + var container = builder.Build(); + _mockFactory.SetupGet(f => f.RuntimeContainer).Returns(container); + _runtime = new ScriptRuntime(_mockFactory.Object); } [Fact] - public void ShouldRegisterTheScriptServices() + public void ShouldResolveLogger() { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); + _runtime.Logger.ShouldEqual(_mockLogger.Object); } - [Fact] - public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() + public void ShouldResolveScriptServices() { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } + _runtime.ScriptServices.ShouldEqual(_scriptServices); - [Fact] - public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); } - [Fact] - public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultFileSystemIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldReturnTheLoggerWhenGetLoggerIsInvoked() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - runtime.Initialize(); - runtime.GetLogger().ShouldEqual(_mockLogger.Object); - } - - [Fact] - public void ShouldReturnTheScriptServiceRootWhenTheGetterIsInvoked() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - runtime.Initialize(); - runtime.GetScriptServices().ShouldNotBeNull(); - - } - - [Fact] - public void ShouldRegisterTheOverriddenScriptHostFactory() - { - var mock = new Mock(); - _overrides[typeof (IScriptHostFactory)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenFilePreProcessor() - { - var mock = new Mock(); - _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - - } - - [Fact] - public void ShouldRegisterTheOverriddenScriptPackResolver() - { - var mock = new Mock(); - _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenInstallationProvider() - { - var mock = new Mock(); - _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenPackageInstaller() - { - var mock = new Mock(); - _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - public class TestFileSystem : FileSystem - { - } - - [Fact] - public void ShouldRegisterTheOverriddenFileSystem() - { - _overrides[typeof(IFileSystem)] = typeof(TestFileSystem); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(); - } - - [Fact] - public void ShouldRegisterTheOverriddenAssemblyUtility() - { - var mock = new Mock(); - _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenPackageContainer() - { - var mock = new Mock(); - _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenPackageAssemblyResolver() - { - var mock = new Mock(); - _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenAssemblyResolver() - { - var mock = new Mock(); - _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenAssemblyResolverInstance() - { - var mock = new Mock(); - _overrides[typeof(IAssemblyResolver)] = mock.Object; - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldEqual(mock.Object); - } - - - - } } } From 36428f453792909801a1b165acca059b28fa9d64 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 24 Jul 2013 13:51:20 -0700 Subject: [PATCH 0359/1224] deleting files --- .../FilePreProcessorResult.cs | 22 --------- src/ScriptCs.Contracts/IAssemblyResolver.cs | 9 ---- src/ScriptCs.Contracts/IAssemblyUtility.cs | 7 --- src/ScriptCs.Contracts/IFilePreProcessor.cs | 11 ----- .../IFilePreProcessorResult.cs | 16 ------- src/ScriptCs.Contracts/IFileSystem.cs | 47 ------------------- .../IPackageAssemblyResolver.cs | 13 ----- src/ScriptCs.Contracts/IScriptCsModule.cs | 14 ------ src/ScriptCs.Contracts/IScriptEngine.cs | 10 ---- src/ScriptCs.Contracts/IScriptExecutor.cs | 13 ----- src/ScriptCs.Contracts/IScriptHostFactory.cs | 11 ----- src/ScriptCs.Contracts/IScriptPackManager.cs | 9 ---- src/ScriptCs.Contracts/IScriptPackResolver.cs | 10 ---- src/ScriptCs.Contracts/IScriptResult.cs | 19 -------- src/ScriptCs.Contracts/IScriptRuntime.cs | 12 ----- .../IScriptRuntimeBuilder.cs | 31 ------------ src/ScriptCs.Contracts/LogLevel.cs | 10 ---- 17 files changed, 264 deletions(-) delete mode 100644 src/ScriptCs.Contracts/FilePreProcessorResult.cs delete mode 100644 src/ScriptCs.Contracts/IAssemblyResolver.cs delete mode 100644 src/ScriptCs.Contracts/IAssemblyUtility.cs delete mode 100644 src/ScriptCs.Contracts/IFilePreProcessor.cs delete mode 100644 src/ScriptCs.Contracts/IFilePreProcessorResult.cs delete mode 100644 src/ScriptCs.Contracts/IFileSystem.cs delete mode 100644 src/ScriptCs.Contracts/IPackageAssemblyResolver.cs delete mode 100644 src/ScriptCs.Contracts/IScriptCsModule.cs delete mode 100644 src/ScriptCs.Contracts/IScriptEngine.cs delete mode 100644 src/ScriptCs.Contracts/IScriptExecutor.cs delete mode 100644 src/ScriptCs.Contracts/IScriptHostFactory.cs delete mode 100644 src/ScriptCs.Contracts/IScriptPackManager.cs delete mode 100644 src/ScriptCs.Contracts/IScriptPackResolver.cs delete mode 100644 src/ScriptCs.Contracts/IScriptResult.cs delete mode 100644 src/ScriptCs.Contracts/IScriptRuntime.cs delete mode 100644 src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs delete mode 100644 src/ScriptCs.Contracts/LogLevel.cs diff --git a/src/ScriptCs.Contracts/FilePreProcessorResult.cs b/src/ScriptCs.Contracts/FilePreProcessorResult.cs deleted file mode 100644 index f5731ebe..00000000 --- a/src/ScriptCs.Contracts/FilePreProcessorResult.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs -{ - public class FilePreProcessorResult - { - public FilePreProcessorResult() - { - UsingStatements = new List(); - LoadedScripts = new List(); - References = new List(); - } - - public List UsingStatements { get; set; } - - public List LoadedScripts { get; set; } - - public List References { get; set; } - - public string Code { get; set; } - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IAssemblyResolver.cs b/src/ScriptCs.Contracts/IAssemblyResolver.cs deleted file mode 100644 index 04bc3338..00000000 --- a/src/ScriptCs.Contracts/IAssemblyResolver.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs -{ - public interface IAssemblyResolver - { - IEnumerable GetAssemblyPaths(string path); - } -} diff --git a/src/ScriptCs.Contracts/IAssemblyUtility.cs b/src/ScriptCs.Contracts/IAssemblyUtility.cs deleted file mode 100644 index 805b4d5b..00000000 --- a/src/ScriptCs.Contracts/IAssemblyUtility.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ScriptCs -{ - public interface IAssemblyUtility - { - bool IsManagedAssembly(string assemblyPath); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IFilePreProcessor.cs b/src/ScriptCs.Contracts/IFilePreProcessor.cs deleted file mode 100644 index d4943eb2..00000000 --- a/src/ScriptCs.Contracts/IFilePreProcessor.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs.Contracts -{ - public interface IFilePreProcessor - { - FilePreProcessorResult ProcessFile(string path); - - FilePreProcessorResult ProcessScript(string script); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IFilePreProcessorResult.cs b/src/ScriptCs.Contracts/IFilePreProcessorResult.cs deleted file mode 100644 index 780d7559..00000000 --- a/src/ScriptCs.Contracts/IFilePreProcessorResult.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - public interface IFilePreProcessorResult - { - List UsingStatements { get; set; } - List LoadedScripts { get; set; } - List References { get; set; } - string Code { get; set; } - } -} diff --git a/src/ScriptCs.Contracts/IFileSystem.cs b/src/ScriptCs.Contracts/IFileSystem.cs deleted file mode 100644 index f4c152ee..00000000 --- a/src/ScriptCs.Contracts/IFileSystem.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace ScriptCs.Contracts -{ - public interface IFileSystem - { - IEnumerable EnumerateFiles(string dir, string search, SearchOption searchOption = SearchOption.AllDirectories); - - void Copy(string source, string dest, bool overwrite); - - bool DirectoryExists(string path); - - void CreateDirectory(string path); - - void DeleteDirectory(string path); - - string ReadFile(string path); - - string[] ReadFileLines(string path); - - DateTime GetLastWriteTime(string file); - - bool IsPathRooted(string path); - - string GetFullPath(string path); - - string CurrentDirectory { get; } - - string NewLine { get; } - - string GetWorkingDirectory(string path); - - void Move(string source, string dest); - - bool FileExists(string path); - - void FileDelete(string path); - - IEnumerable SplitLines(string value); - - void WriteToFile(string path, string text); - - Stream CreateFileStream(string filePath, FileMode mode); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs b/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs deleted file mode 100644 index 62fb4d83..00000000 --- a/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using ScriptCs.Package; - -namespace ScriptCs.Contracts -{ - public interface IPackageAssemblyResolver - { - void SavePackages(Action output); - IEnumerable GetPackages(string workingDirectory); - IEnumerable GetAssemblyNames(string workingDirectory, Action outputCallback = null); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptCsModule.cs b/src/ScriptCs.Contracts/IScriptCsModule.cs deleted file mode 100644 index 3e6855e2..00000000 --- a/src/ScriptCs.Contracts/IScriptCsModule.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - public interface IScriptCsModule - { - void Initialize(IScriptRuntimeBuilder builder); - } -} diff --git a/src/ScriptCs.Contracts/IScriptEngine.cs b/src/ScriptCs.Contracts/IScriptEngine.cs deleted file mode 100644 index b4081283..00000000 --- a/src/ScriptCs.Contracts/IScriptEngine.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs.Contracts -{ - public interface IScriptEngine - { - string BaseDirectory { get; set; } - IScriptResult Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptExecutor.cs b/src/ScriptCs.Contracts/IScriptExecutor.cs deleted file mode 100644 index 8b2c531f..00000000 --- a/src/ScriptCs.Contracts/IScriptExecutor.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ScriptCs.Contracts; -using System.Collections.Generic; - -namespace ScriptCs.Contracts -{ - public interface IScriptExecutor - { - void Initialize(IEnumerable paths, IEnumerable scriptPacks); - ScriptResult Execute(string script, string[] scriptArgs); - ScriptResult Execute(string script); - void Terminate(); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptHostFactory.cs b/src/ScriptCs.Contracts/IScriptHostFactory.cs deleted file mode 100644 index 153ca62c..00000000 --- a/src/ScriptCs.Contracts/IScriptHostFactory.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -using ScriptCs.Contracts; - -namespace ScriptCs.Contracts -{ - public interface IScriptHostFactory - { - ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs); - } -} diff --git a/src/ScriptCs.Contracts/IScriptPackManager.cs b/src/ScriptCs.Contracts/IScriptPackManager.cs deleted file mode 100644 index 2a51a49e..00000000 --- a/src/ScriptCs.Contracts/IScriptPackManager.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ScriptCs.Contracts; - -namespace ScriptCs.Contracts -{ - public interface IScriptPackManager - { - TContext Get() where TContext : IScriptPackContext; - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptPackResolver.cs b/src/ScriptCs.Contracts/IScriptPackResolver.cs deleted file mode 100644 index cf728f0e..00000000 --- a/src/ScriptCs.Contracts/IScriptPackResolver.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ScriptCs.Contracts; -using System.Collections.Generic; - -namespace ScriptCs.Contracts -{ - public interface IScriptPackResolver - { - IEnumerable GetPacks(); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptResult.cs b/src/ScriptCs.Contracts/IScriptResult.cs deleted file mode 100644 index e7b28885..00000000 --- a/src/ScriptCs.Contracts/IScriptResult.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - public interface IScriptResult - { - object ReturnValue { get; set; } - Exception ExecuteException { get; set; } - Exception CompileException { get; set; } - bool ContinueBuffering { get; set; } - bool IsPendingClosingChar { get; set; } - char? ExpectingClosingChar { get; set; } - void UpdateClosingExpectation(Exception ex); - } -} diff --git a/src/ScriptCs.Contracts/IScriptRuntime.cs b/src/ScriptCs.Contracts/IScriptRuntime.cs deleted file mode 100644 index 6717fa06..00000000 --- a/src/ScriptCs.Contracts/IScriptRuntime.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - class IScriptRuntime - { - } -} diff --git a/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs b/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs deleted file mode 100644 index d89bfaef..00000000 --- a/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ScriptCs.Package; -using ScriptCs.Package.InstallationProvider; - -namespace ScriptCs.Contracts -{ - public interface IScriptRuntimeBuilder - { - ScriptRuntime Build(); - IScriptRuntimeBuilder Debug(bool debug = true); - IScriptRuntimeBuilder ScriptName(string name); - IScriptRuntimeBuilder Repl(bool repl = true); - IScriptRuntimeBuilder LogLevel(LogLevel level); - IScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor; - IScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine; - IScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory; - IScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager; - IScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver; - IScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider; - IScriptRuntimeBuilder FileSystem() where T : IFileSystem; - IScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility; - IScriptRuntimeBuilder PackageContainer() where T : IPackageContainer; - IScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor; - IScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver; - IScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor; - } -} diff --git a/src/ScriptCs.Contracts/LogLevel.cs b/src/ScriptCs.Contracts/LogLevel.cs deleted file mode 100644 index bd15dd0e..00000000 --- a/src/ScriptCs.Contracts/LogLevel.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ScriptCs.Contracts -{ - public enum LogLevel - { - Error, - Info, - Debug, - Trace - } -} From b0f9fa4c8bf22a1f7c27dbe534ab67fb69738930 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 02:35:30 -0500 Subject: [PATCH 0360/1224] adding module loader tests --- src/ScriptCs.Hosting/ModuleAttribute.cs | 1 + src/ScriptCs.Hosting/ModuleLoader.cs | 29 ++++--- .../ModuleLoaderTests.cs | 86 +++++++++++++++++++ .../ScriptCs.Hosting.Tests.csproj | 15 ++++ test/ScriptCs.Hosting.Tests/packages.config | 1 + 5 files changed, 121 insertions(+), 11 deletions(-) create mode 100644 test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs diff --git a/src/ScriptCs.Hosting/ModuleAttribute.cs b/src/ScriptCs.Hosting/ModuleAttribute.cs index 6f438db0..095169fb 100644 --- a/src/ScriptCs.Hosting/ModuleAttribute.cs +++ b/src/ScriptCs.Hosting/ModuleAttribute.cs @@ -2,6 +2,7 @@ namespace ScriptCs.Hosting { + [MetadataAttribute] public class ModuleAttribute : ExportAttribute, IModuleMetadata { public ModuleAttribute(string name) : base(typeof (IModule)) diff --git a/src/ScriptCs.Hosting/ModuleLoader.cs b/src/ScriptCs.Hosting/ModuleLoader.cs index 92e81eef..34e441bc 100644 --- a/src/ScriptCs.Hosting/ModuleLoader.cs +++ b/src/ScriptCs.Hosting/ModuleLoader.cs @@ -12,37 +12,44 @@ namespace ScriptCs public class ModuleLoader { private readonly IAssemblyResolver _resolver; - private readonly Action _catalogAction; + private readonly Action _addToCatalog; + private readonly Func>> _getModules; [ImportingConstructor] public ModuleLoader(IAssemblyResolver resolver) : - this(resolver, null) + this(resolver, null, null) { } - public ModuleLoader(IAssemblyResolver resolver, Action catalogAction) + public ModuleLoader(IAssemblyResolver resolver, Action addToCatalog, Func>> getModules) { _resolver = resolver; - _catalogAction = catalogAction; - if (catalogAction == null) - catalogAction = (p, catalog) => catalog.Catalogs.Add(new AssemblyCatalog(p)); + if (addToCatalog == null) + addToCatalog = (p, catalog) => catalog.Catalogs.Add(new AssemblyCatalog(p)); + + _addToCatalog = addToCatalog; + + if (getModules == null) + getModules = (container) => container.GetExports(); + + _getModules = getModules; - _catalogAction = catalogAction; } - public void Load(IScriptRuntimeBuilder builder, string modulePackagesPath, string extension, bool repl, bool debug, string[] moduleNames) + public void Load(IScriptRuntimeBuilder builder, string modulePackagesPath, string extension, bool repl, bool debug, params string[] moduleNames) { var paths = _resolver.GetAssemblyPaths(modulePackagesPath); var catalog = new AggregateCatalog(); foreach (var path in paths) { - _catalogAction(path, catalog); + _addToCatalog(path, catalog); } var container = new CompositionContainer(catalog); - var modules = container.GetExports() + var lazyModules = _getModules(container); + var modules = lazyModules .Where(m => moduleNames.Contains(m.Metadata.Name) || - (extension != null && (m.Metadata.Extensions == extension || m.Metadata.Extensions.Split(',').Contains(extension)))) + (extension != null && m.Metadata.Extensions != null && (m.Metadata.Extensions.Equals(extension) || m.Metadata.Extensions.Split(',').Contains(extension)))) .Select(m => m.Value); foreach (var module in modules) diff --git a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs new file mode 100644 index 00000000..83cfbdf3 --- /dev/null +++ b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Moq; +using Xunit; +using Should; + +namespace ScriptCs.Hosting.Tests +{ + public class ModuleLoaderTests + { + public class TheLoadMethod + { + private Mock _mockAssemblyResolver = new Mock(); + private IList _paths = new List(); + private IList> _modules = new List>(); + private Func>> _getModules; + private Mock _mockModule1 = new Mock(); + private Mock _mockModule2 = new Mock(); + private Mock _mockModule3 = new Mock(); + + public TheLoadMethod() + { + var paths = new [] {"path1", "path2"}; + _mockAssemblyResolver.Setup(r => r.GetAssemblyPaths(It.IsAny())).Returns(paths); + _modules.Add(new Lazy(()=>_mockModule1.Object, new ModuleMetadata {Extensions="ext1,ext2", Name="module1"})); + _modules.Add(new Lazy(() => _mockModule2.Object, new ModuleMetadata { Extensions = "ext3,ext4", Name = "module2" })); + _modules.Add(new Lazy(() => _mockModule3.Object, new ModuleMetadata { Name = "module3" })); + _getModules = c => _modules; + + } + + [Fact] + public void ShouldResolvePathsFromTheAssemblyResolver() + { + var loader = new ModuleLoader(_mockAssemblyResolver.Object, (p,c) => { }, c => Enumerable.Empty>()); + loader.Load(null, "c:\test", null, false, false); + _mockAssemblyResolver.Verify(r=>r.GetAssemblyPaths("c:\test")); + } + + [Fact] + public void ShouldInvokeTheCatalogActionForEachFile() + { + var loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), c => Enumerable.Empty>()); + loader.Load(null, "c:\test", null, false, false); + _paths.Count.ShouldEqual(2); + } + + [Fact] + public void ShouldInitializeModulesThatMatchOnExtension() + { + var loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), _getModules); + loader.Load(null, null, "ext1", false, false); + _mockModule1.Verify(m=>m.Initialize(It.IsAny(), false, false), Times.Once()); + _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + + loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), _getModules); + loader.Load(null, null, "ext3", false, false); + _mockModule1.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Once()); + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + + } + + [Fact] + public void ShouldInitializeModulesTheMatchBasedOnName() + { + var loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), _getModules); + loader.Load(null, null, null, false, false, "module3"); + _mockModule1.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Once()); + } + + public class ModuleMetadata : IModuleMetadata + { + public string Name { get; set; } + public string Extensions { get; set; } + } + } + } +} diff --git a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj index 54bed027..6e3a28b3 100644 --- a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj +++ b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj @@ -10,12 +10,22 @@ ..\..\ + + ..\ScriptCs.Tests\bin\Debug\Moq.dll + + + ..\..\packages\Should.1.1.12.0\lib\Should.dll + + ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + ..\ScriptCs.Tests\bin\Debug\xunit.extensions.dll + @@ -24,12 +34,17 @@ Properties\CommonVersionInfo.cs + + + {E590E710-E159-48E6-A3E6-1A83D3FE732C} + ScriptCs.Core + {9aef2d95-87fb-4829-b384-34bfe076d531} ScriptCs.Hosting diff --git a/test/ScriptCs.Hosting.Tests/packages.config b/test/ScriptCs.Hosting.Tests/packages.config index 7c4280d1..5aa03453 100644 --- a/test/ScriptCs.Hosting.Tests/packages.config +++ b/test/ScriptCs.Hosting.Tests/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file From 6e81cc863ae89d8e52964b42ffbab9c74be0e4b2 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 03:48:56 -0500 Subject: [PATCH 0361/1224] Fixing registering all services as singletons, adding -install -g and -clean -g support --- src/ScriptCs.Core/FileSystem.cs | 6 ++++ src/ScriptCs.Core/IFileSystem.cs | 4 ++- .../IInstallationProvider.cs | 1 + .../NugetInstallationProvider.cs | 12 +++++--- src/ScriptCs.Core/ScriptContainerFactory.cs | 30 +++++++++---------- src/ScriptCs.Core/ScriptServices.cs | 7 ++++- src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs | 6 ++-- src/ScriptCs/Command/CommandFactory.cs | 25 ++++++++++++++-- src/ScriptCs/Command/InstallCommand.cs | 10 +++++-- src/ScriptCs/ScriptCsArgs.cs | 5 ++++ 10 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 41e9c6c3..ab04a878 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -49,6 +49,7 @@ public bool IsPathRooted(string path) public string CurrentDirectory { get { return Environment.CurrentDirectory; } + set { Environment.CurrentDirectory = value; } } public string NewLine @@ -93,6 +94,11 @@ public Stream CreateFileStream(string filePath, FileMode mode) return new FileStream(filePath, mode); } + public string LocalApplicationData + { + get { return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); } + } + public string GetWorkingDirectory(string path) { if (string.IsNullOrWhiteSpace(path)) diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index fdb62ce3..37ec5696 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -26,7 +26,7 @@ public interface IFileSystem string GetFullPath(string path); - string CurrentDirectory { get; } + string CurrentDirectory { get; set; } string NewLine { get; } @@ -43,5 +43,7 @@ public interface IFileSystem void WriteToFile(string path, string text); Stream CreateFileStream(string filePath, FileMode mode); + + string LocalApplicationData { get; } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs index 5d8fe5c9..299b5e43 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs @@ -6,6 +6,7 @@ namespace ScriptCs.Package.InstallationProvider public interface IInstallationProvider { IEnumerable GetRepositorySources(string path); + void Initialize(); bool IsInstalled(IPackageReference packageId, bool allowPreRelease = false); bool InstallPackage(IPackageReference packageId, bool allowPreRelease = false, Action packageInstalled = null); } diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index 1edb0dc8..6eab329c 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -8,9 +8,9 @@ namespace ScriptCs.Package.InstallationProvider { public class NugetInstallationProvider : IInstallationProvider { - private readonly IFileSystem _fileSystem; - private readonly PackageManager _manager; - private readonly IEnumerable _repositoryUrls; + private IFileSystem _fileSystem; + private PackageManager _manager; + private IEnumerable _repositoryUrls; private static readonly Version EmptyVersion = new Version(); @@ -19,7 +19,11 @@ public NugetInstallationProvider(IFileSystem fileSystem) Guard.AgainstNullArgument("fileSystem", fileSystem); _fileSystem = fileSystem; - var path = Path.Combine(fileSystem.CurrentDirectory, Constants.PackagesFolder); + } + + public void Initialize() + { + var path = Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFolder); _repositoryUrls = GetRepositorySources(path); var remoteRepository = new AggregateRepository(PackageRepositoryFactory.Default, _repositoryUrls, true); _manager = new PackageManager(remoteRepository, path); diff --git a/src/ScriptCs.Core/ScriptContainerFactory.cs b/src/ScriptCs.Core/ScriptContainerFactory.cs index f232787b..844a0f49 100644 --- a/src/ScriptCs.Core/ScriptContainerFactory.cs +++ b/src/ScriptCs.Core/ScriptContainerFactory.cs @@ -71,11 +71,11 @@ private IContainer CreateInitializationContainer() { var builder = new ContainerBuilder(); builder.RegisterInstance(_logger); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); return builder.Build(); } @@ -83,17 +83,17 @@ private IContainer CreateRuntimeContainer() { var builder = new ContainerBuilder(); builder.RegisterInstance(_logger).Exported(x => x.As()); - builder.RegisterType(_scriptEngineType).As(); - builder.RegisterType(_scriptExecutorType).As(); + builder.RegisterType(_scriptEngineType).As().SingleInstance(); + builder.RegisterType(_scriptExecutorType).As().SingleInstance(); builder.RegisterInstance(_console).As(); - builder.RegisterType(); - - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType()); + builder.RegisterType().SingleInstance(); + + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().SingleInstance()); var initializationContainer = InitializationContainer; var assemblyResolver = initializationContainer.Resolve(); diff --git a/src/ScriptCs.Core/ScriptServices.cs b/src/ScriptCs.Core/ScriptServices.cs index a144d45e..315fcd4c 100644 --- a/src/ScriptCs.Core/ScriptServices.cs +++ b/src/ScriptCs.Core/ScriptServices.cs @@ -1,6 +1,7 @@ using Common.Logging; using ScriptCs.Contracts; using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; namespace ScriptCs { @@ -16,7 +17,9 @@ public ScriptServices( IPackageInstaller packageInstaller, ILog logger, IAssemblyResolver assemblyResolver, - IConsole console = null) + IConsole console = null, + IInstallationProvider installationProvider = null + ) { FileSystem = fileSystem; PackageAssemblyResolver = packageAssemblyResolver; @@ -28,6 +31,7 @@ public ScriptServices( Logger = logger; Console = console; AssemblyResolver = assemblyResolver; + InstallationProvider = installationProvider; } public IFileSystem FileSystem { get; private set; } @@ -40,5 +44,6 @@ public ScriptServices( public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } public IAssemblyResolver AssemblyResolver { get; private set; } + public IInstallationProvider InstallationProvider { get; private set; } } } diff --git a/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs index 3cf69f23..9487efd8 100644 --- a/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs +++ b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs @@ -39,8 +39,10 @@ public ScriptRuntime Build() } var loggerConfigurator = new LoggerConfigurator(_logLevel); - var initDirectoryCatalog = _scriptName.Length > 0 || _repl; - var factory = new ScriptContainerFactory(loggerConfigurator.GetLogger(), new ScriptConsole(), _scriptEngineType, _scriptExecutorType, initDirectoryCatalog, _overrides); + var console = new ScriptConsole(); + loggerConfigurator.Configure(console); + var initDirectoryCatalog = _scriptName != null || _repl; + var factory = new ScriptContainerFactory(loggerConfigurator.GetLogger(), console, _scriptEngineType, _scriptExecutorType, initDirectoryCatalog, _overrides); var runtime = new ScriptRuntime(factory); return runtime; } diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 082baea6..ff448ec1 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -74,9 +74,22 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServices.FileSystem, _scriptServices.PackageAssemblyResolver, _scriptServices.PackageInstaller, - _scriptServices.Logger); + _scriptServices.Logger + ); + + string currentDirectory = null; + + if (args.Global) + { + currentDirectory = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); + _scriptServices.FileSystem.CurrentDirectory = currentDirectory; + if (!_scriptServices.FileSystem.DirectoryExists(currentDirectory)) + _scriptServices.FileSystem.CreateDirectory(currentDirectory); + } + else + currentDirectory = _scriptServices.FileSystem.CurrentDirectory; - var currentDirectory = _scriptServices.FileSystem.CurrentDirectory; + _scriptServices.InstallationProvider.Initialize(); var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); if (!_scriptServices.FileSystem.FileExists(packageFile)) @@ -92,6 +105,14 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) { var saveCommand = new SaveCommand(_scriptServices.PackageAssemblyResolver); + if (args.Global) + { + var currentDirectory = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); + _scriptServices.FileSystem.CurrentDirectory = currentDirectory; + if (!_scriptServices.FileSystem.DirectoryExists(currentDirectory)) + _scriptServices.FileSystem.CreateDirectory(currentDirectory); + } + var cleanCommand = new CleanCommand( args.ScriptName, _scriptServices.FileSystem, diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index 319d79bf..293094f8 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.Versioning; using Common.Logging; using ScriptCs.Package; @@ -26,7 +27,8 @@ public InstallCommand( IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IPackageInstaller packageInstaller, - ILog logger) + ILog logger + ) { _name = name; _allowPre = allowPre; @@ -38,11 +40,13 @@ public InstallCommand( public CommandResult Execute() { - _logger.Info("Installing packages..."); var workingDirectory = _fileSystem.CurrentDirectory; + _logger.Info("Installing packages..."); + _logger.TraceFormat("Packages folder: {0}", Path.Combine(workingDirectory, "Packages")); + var packages = GetPackages(workingDirectory); - + try { _packageInstaller.InstallPackages(packages, _allowPre, _logger.Info); diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index a8009099..0dcba45e 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -34,6 +34,11 @@ public class ScriptCsArgs [ArgDescription("Installs and restores packages which are specified in packages.config")] public string Install { get; set; } + [ArgShortcut("g")] + [ArgDescription("Installs and restores global packages which are specified in packages.config")] + public bool Global { get; set; } + + [ArgShortcut("save")] [ArgDescription("Creates a packages.config file based on the packages directory")] public bool Save { get; set; } From 5b25a70c7d22060eb5629a6d5c3cf001dca51091 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 04:10:59 -0500 Subject: [PATCH 0362/1224] cleanup / bug fixing --- common/CommonVersionInfo.cs | 21 ++++++++++++----- src/ScriptCs/Command/CommandFactory.cs | 23 +++++++++++-------- .../ModuleLoaderTests.cs | 7 ------ .../ScriptCs.Hosting.Tests.csproj | 3 ++- test/ScriptCs.Hosting.Tests/packages.config | 1 + 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index 590a13eb..e8a62e22 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,9 +1,18 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; using System.Reflection; -/** - * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the - * contents of 'build\ScriptCs.Version.props'. - **/ +[assembly: System.Reflection.AssemblyVersionAttribute("0.6.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("0.6.0-alpha")] + +// Generated by the MSBuild WriteCodeFragment class on 7/25/2013 4:08:10 AM. -[assembly: AssemblyVersion("0.0.0")] -[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index ff448ec1..e78dcb86 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -20,6 +20,18 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) return new ShowUsageCommand(_scriptServices.Logger, isValid: true); } + if (args.Global) + { + var currentDir = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); + _scriptServices.FileSystem.CurrentDirectory = currentDir; + + if (!_scriptServices.FileSystem.DirectoryExists(currentDir)) + _scriptServices.FileSystem.CreateDirectory(currentDir); + + } + + _scriptServices.InstallationProvider.Initialize(); + if (args.Repl) { var replCommand = new ExecuteReplCommand( @@ -79,17 +91,8 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) string currentDirectory = null; - if (args.Global) - { - currentDirectory = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); - _scriptServices.FileSystem.CurrentDirectory = currentDirectory; - if (!_scriptServices.FileSystem.DirectoryExists(currentDirectory)) - _scriptServices.FileSystem.CreateDirectory(currentDirectory); - } - else - currentDirectory = _scriptServices.FileSystem.CurrentDirectory; + currentDirectory = _scriptServices.FileSystem.CurrentDirectory; - _scriptServices.InstallationProvider.Initialize(); var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); if (!_scriptServices.FileSystem.FileExists(packageFile)) diff --git a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs index 83cfbdf3..e1552d5a 100644 --- a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs +++ b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs @@ -57,13 +57,6 @@ public void ShouldInitializeModulesThatMatchOnExtension() _mockModule1.Verify(m=>m.Initialize(It.IsAny(), false, false), Times.Once()); _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - - loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), _getModules); - loader.Load(null, null, "ext3", false, false); - _mockModule1.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Once()); - _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - } [Fact] diff --git a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj index 6e3a28b3..3d3a01e9 100644 --- a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj +++ b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj @@ -11,7 +11,8 @@ - ..\ScriptCs.Tests\bin\Debug\Moq.dll + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll + True ..\..\packages\Should.1.1.12.0\lib\Should.dll diff --git a/test/ScriptCs.Hosting.Tests/packages.config b/test/ScriptCs.Hosting.Tests/packages.config index 5aa03453..08b40aa8 100644 --- a/test/ScriptCs.Hosting.Tests/packages.config +++ b/test/ScriptCs.Hosting.Tests/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file From 20b973703efb337a1f7c9887aed8fdb5632d713b Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 04:18:45 -0500 Subject: [PATCH 0363/1224] fix order of creation for module folder --- src/ScriptCs/Command/CommandFactory.cs | 5 ++--- test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index e78dcb86..5b47726e 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -23,11 +23,10 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Global) { var currentDir = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); - _scriptServices.FileSystem.CurrentDirectory = currentDir; - if (!_scriptServices.FileSystem.DirectoryExists(currentDir)) _scriptServices.FileSystem.CreateDirectory(currentDir); - + + _scriptServices.FileSystem.CurrentDirectory = currentDir; } _scriptServices.InstallationProvider.Initialize(); diff --git a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs index e1552d5a..3426f0eb 100644 --- a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs +++ b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs @@ -56,7 +56,7 @@ public void ShouldInitializeModulesThatMatchOnExtension() loader.Load(null, null, "ext1", false, false); _mockModule1.Verify(m=>m.Initialize(It.IsAny(), false, false), Times.Once()); _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never());g } [Fact] From 7c369e88cf147be7f17bef6f6e8015df25e699fa Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 04:21:25 -0500 Subject: [PATCH 0364/1224] fix typo in test --- test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs index 3426f0eb..e1552d5a 100644 --- a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs +++ b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs @@ -56,7 +56,7 @@ public void ShouldInitializeModulesThatMatchOnExtension() loader.Load(null, null, "ext1", false, false); _mockModule1.Verify(m=>m.Initialize(It.IsAny(), false, false), Times.Once()); _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never());g + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); } [Fact] From be2786e0e51d3190f598a52d5b707c1843ad9b3b Mon Sep 17 00:00:00 2001 From: Brandon Stirnaman Date: Thu, 25 Jul 2013 09:58:27 -0500 Subject: [PATCH 0365/1224] Fixes scriptcs/scriptcs#375 - line splitting when linebreaks differ between Host and file --- src/ScriptCs.Core/FileSystem.cs | 2 +- test/ScriptCs.Core.Tests/FileSystemTests.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index ab04a878..c481e082 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -81,7 +81,7 @@ public IEnumerable SplitLines(string value) { Guard.AgainstNullArgument("value", value); - return value.Split(new[] { NewLine }, StringSplitOptions.None); + return value.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None); } public void WriteToFile(string path, string text) diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs index f683eedf..7c8b1ee7 100644 --- a/test/ScriptCs.Core.Tests/FileSystemTests.cs +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.IO; using Should; using Xunit; @@ -80,5 +81,20 @@ public void ReturnsCorrectWorkingDirectoryIfPathDoesNotExist() _fileSystem.GetWorkingDirectory(nonExistantFilePath).ShouldEqual(@"C:\working_dir"); } } + + public class SplitLinesMethod + { + private readonly FileSystem _fileSystem = new FileSystem(); + + [Fact] + public void ReturnsCorrectLines() + { + var fileContentsLin = "using System;\nusing System.IO;"; + var fileContentsWin = "using System;\r\nusing System.IO;"; + + _fileSystem.SplitLines(fileContentsLin).Count().ShouldEqual(2); + _fileSystem.SplitLines(fileContentsWin).Count().ShouldEqual(2); + } + } } } \ No newline at end of file From 32ec49137dbe874c85751c07a7d8fc1c11861f48 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 26 Jul 2013 01:55:24 -0500 Subject: [PATCH 0366/1224] Refactored into separate container factories, necessary for wiring up modules --- src/ScriptCs.Core/IRuntimeContainerFactory.cs | 9 ++ src/ScriptCs.Core/IScriptContainerFactory.cs | 10 -- .../InitializationContainerFactory.cs | 36 ++++++ src/ScriptCs.Core/RuntimeContainerFactory.cs | 74 +++++++++++ src/ScriptCs.Core/ScriptContainerFactory.cs | 122 +++--------------- src/ScriptCs.Core/ScriptCs.Core.csproj | 4 +- src/ScriptCs.Core/ScriptRuntime.cs | 10 +- src/ScriptCs.Hosting/ModuleAttribute.cs | 2 +- src/ScriptCs.Hosting/ScriptCs.Hosting.csproj | 53 ++++++-- src/ScriptCs.Hosting/packages.config | 9 ++ src/ScriptCs/ModuleAttribute.cs | 14 -- src/ScriptCs/Program.cs | 4 - src/ScriptCs/Properties/Settings.Designer.cs | 26 ++++ src/ScriptCs/Properties/Settings.settings | 6 + src/ScriptCs/ScriptCs.csproj | 42 +++++- src/ScriptCs/ScriptCsArgs.cs | 4 + .../InitializationContainerFactoryTests.cs | 21 +++ ...sts.cs => RuntimeContainerFactoryTests.cs} | 63 +++++---- .../ScriptCs.Core.Tests.csproj | 3 +- .../ScriptCs.Core.Tests/ScriptRuntimeTests.cs | 4 +- 20 files changed, 331 insertions(+), 185 deletions(-) create mode 100644 src/ScriptCs.Core/IRuntimeContainerFactory.cs delete mode 100644 src/ScriptCs.Core/IScriptContainerFactory.cs create mode 100644 src/ScriptCs.Core/InitializationContainerFactory.cs create mode 100644 src/ScriptCs.Core/RuntimeContainerFactory.cs delete mode 100644 src/ScriptCs/ModuleAttribute.cs create mode 100644 src/ScriptCs/Properties/Settings.Designer.cs create mode 100644 src/ScriptCs/Properties/Settings.settings create mode 100644 test/ScriptCs.Core.Tests/InitializationContainerFactoryTests.cs rename test/ScriptCs.Core.Tests/{ScriptContainerFactoryTests.cs => RuntimeContainerFactoryTests.cs} (65%) diff --git a/src/ScriptCs.Core/IRuntimeContainerFactory.cs b/src/ScriptCs.Core/IRuntimeContainerFactory.cs new file mode 100644 index 00000000..12523461 --- /dev/null +++ b/src/ScriptCs.Core/IRuntimeContainerFactory.cs @@ -0,0 +1,9 @@ +using Autofac; + +namespace ScriptCs +{ + public interface IRuntimeContainerFactory + { + IContainer Container { get; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptContainerFactory.cs b/src/ScriptCs.Core/IScriptContainerFactory.cs deleted file mode 100644 index a9420f34..00000000 --- a/src/ScriptCs.Core/IScriptContainerFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Autofac; - -namespace ScriptCs -{ - public interface IScriptContainerFactory - { - IContainer InitializationContainer { get; } - IContainer RuntimeContainer { get; } - } -} \ No newline at end of file diff --git a/src/ScriptCs.Core/InitializationContainerFactory.cs b/src/ScriptCs.Core/InitializationContainerFactory.cs new file mode 100644 index 00000000..5991e486 --- /dev/null +++ b/src/ScriptCs.Core/InitializationContainerFactory.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Common.Logging; +using ScriptCs.Package; + +namespace ScriptCs +{ + public interface IInitializationContainerFactory + { + IContainer Container { get; } + } + + public class InitializationContainerFactory : ScriptContainerFactory, IInitializationContainerFactory + { + public InitializationContainerFactory(ILog logger, IDictionary overrides) + : base(logger, overrides) + { + } + + protected override IContainer CreateContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(_logger); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + return builder.Build(); + } + } +} diff --git a/src/ScriptCs.Core/RuntimeContainerFactory.cs b/src/ScriptCs.Core/RuntimeContainerFactory.cs new file mode 100644 index 00000000..81d6d961 --- /dev/null +++ b/src/ScriptCs.Core/RuntimeContainerFactory.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Autofac.Integration.Mef; +using Common.Logging; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs +{ + public class RuntimeContainerFactory : ScriptContainerFactory, IRuntimeContainerFactory + { + private readonly IConsole _console; + private readonly Type _scriptEngineType; + private readonly Type _scriptExecutorType; + private readonly bool _initDirectoryCatalog; + private readonly IInitializationContainerFactory _initializationContainerFactory; + + public RuntimeContainerFactory(ILog logger, IDictionary overrides, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IInitializationContainerFactory initializationContainerFactory) : + base(logger, overrides) + { + _console = console; + _scriptEngineType = scriptEngineType; + _scriptExecutorType = scriptExecutorType; + _initDirectoryCatalog = initDirectoryCatalog; + _initializationContainerFactory = initializationContainerFactory; + } + + protected override IContainer CreateContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(_logger).Exported(x => x.As()); + builder.RegisterType(_scriptEngineType).As().SingleInstance(); + builder.RegisterType(_scriptExecutorType).As().SingleInstance(); + builder.RegisterInstance(_console).As(); + builder.RegisterType().SingleInstance(); + + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().SingleInstance()); + var initializationContainer = _initializationContainerFactory.Container; + var assemblyResolver = initializationContainer.Resolve(); + + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(assemblyResolver).As(); + + if (_initDirectoryCatalog) + { + var currentDirectory = Environment.CurrentDirectory; + var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); + + var aggregateCatalog = new AggregateCatalog(); + + assemblies.Select(x => new AssemblyCatalog(x)).ToList() + .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); + + builder.RegisterComposablePartCatalog(aggregateCatalog); + } + + return builder.Build(); + } + } +} diff --git a/src/ScriptCs.Core/ScriptContainerFactory.cs b/src/ScriptCs.Core/ScriptContainerFactory.cs index 844a0f49..6326b594 100644 --- a/src/ScriptCs.Core/ScriptContainerFactory.cs +++ b/src/ScriptCs.Core/ScriptContainerFactory.cs @@ -14,113 +14,18 @@ namespace ScriptCs { - public class ScriptContainerFactory : IScriptContainerFactory + public abstract class ScriptContainerFactory { - private readonly ILog _logger; - private readonly IConsole _console; - private readonly Type _scriptEngineType; - private readonly Type _scriptExecutorType; - private readonly bool _initDirectoryCatalog; - private IDictionary _overrides = null; + private readonly IDictionary _overrides = null; + protected readonly ILog _logger; - public ScriptContainerFactory(ILog logger, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IDictionary overrides ) + public ScriptContainerFactory(ILog logger, IDictionary overrides) { - Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); - Guard.AgainstNullArgument("scriptEngine", scriptEngineType); - Guard.AgainstNullArgument("console", console); - Guard.AgainstNullArgument("logger", logger); - - if (overrides == null) - overrides = new Dictionary(); - - _logger = logger; - _console = console; - _scriptEngineType = scriptEngineType; - _scriptExecutorType = scriptExecutorType; - _initDirectoryCatalog = initDirectoryCatalog; _overrides = overrides; + _logger = logger; } - private IContainer _initializationContainer; - public IContainer InitializationContainer - { - get - { - if (_initializationContainer == null) - { - _initializationContainer = CreateInitializationContainer(); - } - return _initializationContainer; - } - } - - private IContainer _runtimeContainer; - public IContainer RuntimeContainer - { - get - { - if (_runtimeContainer == null) - { - _runtimeContainer = CreateRuntimeContainer(); - } - return _runtimeContainer; - } - } - - private IContainer CreateInitializationContainer() - { - var builder = new ContainerBuilder(); - builder.RegisterInstance(_logger); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - return builder.Build(); - } - - private IContainer CreateRuntimeContainer() - { - var builder = new ContainerBuilder(); - builder.RegisterInstance(_logger).Exported(x => x.As()); - builder.RegisterType(_scriptEngineType).As().SingleInstance(); - builder.RegisterType(_scriptExecutorType).As().SingleInstance(); - builder.RegisterInstance(_console).As(); - builder.RegisterType().SingleInstance(); - - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().SingleInstance()); - - var initializationContainer = InitializationContainer; - var assemblyResolver = initializationContainer.Resolve(); - - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(assemblyResolver).As(); - - if (_initDirectoryCatalog) - { - var currentDirectory = Environment.CurrentDirectory; - var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); - - var aggregateCatalog = new AggregateCatalog(); - - assemblies.Select(x => new AssemblyCatalog(x)).ToList() - .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); - - builder.RegisterComposablePartCatalog(aggregateCatalog); - } - - return builder.Build(); - } - - private void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) + protected void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) { if (_overrides.ContainsKey(typeof(T))) { @@ -139,5 +44,20 @@ private void RegisterOverrideOrDefault(ContainerBuilder builder, Action - + + + diff --git a/src/ScriptCs.Core/ScriptRuntime.cs b/src/ScriptCs.Core/ScriptRuntime.cs index ea8182f6..d84f5151 100644 --- a/src/ScriptCs.Core/ScriptRuntime.cs +++ b/src/ScriptCs.Core/ScriptRuntime.cs @@ -15,15 +15,17 @@ namespace ScriptCs { public class ScriptRuntime { + /* public ScriptRuntime(ILog logger, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IDictionary overrides) - : this(new ScriptContainerFactory(logger, console, scriptEngineType, scriptExecutorType, initDirectoryCatalog, overrides)) + : this(new RuntimeContainerFactory(logger, console, scriptEngineType, scriptExecutorType, initDirectoryCatalog)) { } - - public ScriptRuntime(IScriptContainerFactory containerFactory) + */ + + public ScriptRuntime(IRuntimeContainerFactory containerFactory) { - var container = containerFactory.RuntimeContainer; + var container = containerFactory.Container; ScriptServices = container.Resolve(); Logger = container.Resolve(); } diff --git a/src/ScriptCs.Hosting/ModuleAttribute.cs b/src/ScriptCs.Hosting/ModuleAttribute.cs index 095169fb..d940f524 100644 --- a/src/ScriptCs.Hosting/ModuleAttribute.cs +++ b/src/ScriptCs.Hosting/ModuleAttribute.cs @@ -1,6 +1,6 @@ using System.ComponentModel.Composition; -namespace ScriptCs.Hosting +namespace ScriptCs { [MetadataAttribute] public class ModuleAttribute : ExportAttribute, IModuleMetadata diff --git a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index 179dd3c6..b81aef24 100644 --- a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -9,6 +9,17 @@ ..\ + + False + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.Configuration.dll + + + False + ..\..\packages\Autofac.Mef.3.0.1\lib\net40\Autofac.Integration.Mef.dll + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll @@ -18,6 +29,34 @@ ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll + + False + ..\..\packages\NuGet.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + + + True + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + + + True + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + + + False + ..\..\packages\ScriptCs.Contracts.0.6.0-alpha\lib\net45\ScriptCs.Contracts.dll + + + False + ..\..\packages\ScriptCs.Core.0.6.0-alpha\lib\net45\ScriptCs.Core.dll + + + False + ..\..\packages\ScriptCs.Engine.Roslyn.0.6.0-alpha\lib\net45\ScriptCs.Engine.Roslyn.dll + + + False + ..\..\packages\ServiceStack.Text.3.9.56\lib\net35\ServiceStack.Text.dll + @@ -27,20 +66,6 @@ - - - {6049e205-8b5f-4080-b023-70600e51fd64} - ScriptCs.Contracts - - - {e590e710-e159-48e6-a3e6-1a83d3fe732c} - ScriptCs.Core - - - {e79ec231-e27d-4057-91c9-2d001a3a8c3b} - ScriptCs.Engine.Roslyn - - Properties\CommonAssemblyInfo.cs diff --git a/src/ScriptCs.Hosting/packages.config b/src/ScriptCs.Hosting/packages.config index 8ec4ed08..5a7fb1a4 100644 --- a/src/ScriptCs.Hosting/packages.config +++ b/src/ScriptCs.Hosting/packages.config @@ -1,6 +1,15 @@  + + + + + + + + + \ No newline at end of file diff --git a/src/ScriptCs/ModuleAttribute.cs b/src/ScriptCs/ModuleAttribute.cs deleted file mode 100644 index c02bb5ec..00000000 --- a/src/ScriptCs/ModuleAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.Composition; - -namespace ScriptCs.Hosting -{ - public class ModuleAttribute : ExportAttribute - { - public ModuleAttribute(string name) : base(typeof (IModule)) - { - Name = name; - } - - public string Name { get; private set; } - } -} \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 5039329c..c55f3719 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -22,10 +22,6 @@ private static int Main(string[] args) ScriptName(commandArgs.ScriptName). Repl(commandArgs.Repl); - var containerBuilder = new ContainerBuilder(); - - - var runtime = runtimeBuilder.Build(); var logger = runtime.Logger; diff --git a/src/ScriptCs/Properties/Settings.Designer.cs b/src/ScriptCs/Properties/Settings.Designer.cs new file mode 100644 index 00000000..0f094d02 --- /dev/null +++ b/src/ScriptCs/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ScriptCs.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/src/ScriptCs/Properties/Settings.settings b/src/ScriptCs/Properties/Settings.settings new file mode 100644 index 00000000..049245f4 --- /dev/null +++ b/src/ScriptCs/Properties/Settings.settings @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 83d09dc3..ccf0792c 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -8,6 +8,21 @@ scriptcs ..\..\ ..\..\build\ScriptCs.ruleset + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true ..\..\common\Icon.ico @@ -73,7 +88,11 @@ - + + True + True + Settings.settings + @@ -84,6 +103,10 @@ + + SettingsSingleFileGenerator + Settings.Designer.cs + @@ -108,6 +131,23 @@ Properties\Icon.ico + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + \ No newline at end of file diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 0dcba45e..1c9f3662 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -55,6 +55,10 @@ public class ScriptCsArgs [ArgDescription("Outputs version information")] public bool Version { get; set; } + [ArgShortcut("modules")] + [ArgDescription("Specify modules to load")] + public string Modules { get; set; } + public static void SplitScriptArgs(ref string[] args, out string[] scriptArgs) { Guard.AgainstNullArgument("args", args); diff --git a/test/ScriptCs.Core.Tests/InitializationContainerFactoryTests.cs b/test/ScriptCs.Core.Tests/InitializationContainerFactoryTests.cs new file mode 100644 index 00000000..1d55d586 --- /dev/null +++ b/test/ScriptCs.Core.Tests/InitializationContainerFactoryTests.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using Autofac; +using Common.Logging; +using Moq; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class InitializationContainerFactoryTests + { + public class TheCreateInitializationContainerMethod + { + + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs b/test/ScriptCs.Core.Tests/RuntimeContainerFactoryTests.cs similarity index 65% rename from test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs rename to test/ScriptCs.Core.Tests/RuntimeContainerFactoryTests.cs index fd0c385d..24718000 100644 --- a/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs +++ b/test/ScriptCs.Core.Tests/RuntimeContainerFactoryTests.cs @@ -14,7 +14,7 @@ namespace ScriptCs.Tests { - public class ScriptContainerFactoryTests + public class RuntimeContainerFactoryTests { public class TheCreateInitializationContainerMethod { @@ -28,7 +28,7 @@ public class TheCreateRuntimeContainerMethod private Type _scriptEngineType = null; private Mock _mockLogger = new Mock(); private IDictionary _overrides = new Dictionary(); - private IScriptContainerFactory _factory = null; + private IRuntimeContainerFactory _runtimeContainerFactory = null; public TheCreateRuntimeContainerMethod() { @@ -38,106 +38,107 @@ public TheCreateRuntimeContainerMethod() var mockScriptEngineType = new Mock(); _scriptEngineType = mockScriptEngineType.Object.GetType(); - _factory = new ScriptContainerFactory(_mockLogger.Object, _mockConsole.Object, _scriptEngineType, _scriptExecutorType, false, _overrides); + var initializationContainerFactory = new InitializationContainerFactory(_mockLogger.Object, _overrides); + _runtimeContainerFactory = new RuntimeContainerFactory(_mockLogger.Object, _overrides, _mockConsole.Object, _scriptEngineType, _scriptExecutorType, false, initializationContainerFactory); } [Fact] public void ShouldRegisterTheLoggerInstance() { - var logger = _factory.RuntimeContainer.Resolve(); + var logger = _runtimeContainerFactory.Container.Resolve(); logger.ShouldEqual(_mockLogger.Object); } [Fact] public void ShouldRegisterTheScriptEngine() { - var engine = _factory.RuntimeContainer.Resolve(); + var engine = _runtimeContainerFactory.Container.Resolve(); engine.GetType().ShouldEqual(_scriptEngineType); } [Fact] public void ShouldRegisterTheExecutor() { - var executor = _factory.RuntimeContainer.Resolve(); + var executor = _runtimeContainerFactory.Container.Resolve(); executor.GetType().ShouldEqual(_scriptExecutorType); } [Fact] public void ShouldRegisterTheConsoleInstance() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheScriptServices() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultFileSystemIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] @@ -145,7 +146,7 @@ public void ShouldRegisterTheOverriddenScriptHostFactory() { var mock = new Mock(); _overrides[typeof(IScriptHostFactory)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -153,7 +154,7 @@ public void ShouldRegisterTheOverriddenFilePreProcessor() { var mock = new Mock(); _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -162,7 +163,7 @@ public void ShouldRegisterTheOverriddenScriptPackResolver() { var mock = new Mock(); _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -170,7 +171,7 @@ public void ShouldRegisterTheOverriddenInstallationProvider() { var mock = new Mock(); _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -178,7 +179,7 @@ public void ShouldRegisterTheOverriddenPackageInstaller() { var mock = new Mock(); _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -186,7 +187,7 @@ public void ShouldRegisterTheOverriddenFileSystem() { var mock = new Mock(); _overrides[typeof(IFileSystem)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -194,7 +195,7 @@ public void ShouldRegisterTheOverriddenAssemblyUtility() { var mock = new Mock(); _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -202,7 +203,7 @@ public void ShouldRegisterTheOverriddenPackageContainer() { var mock = new Mock(); _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -210,17 +211,15 @@ public void ShouldRegisterTheOverriddenPackageAssemblyResolver() { var mock = new Mock(); _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } - - [Fact] public void ShouldRegisterTheOverriddenAssemblyResolver() { var mock = new Mock(); _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -228,7 +227,7 @@ public void ShouldRegisterTheOverriddenAssemblyResolverInstance() { var mock = new Mock(); _overrides[typeof(IAssemblyResolver)] = mock.Object; - _factory.RuntimeContainer.Resolve().ShouldEqual(mock.Object); + _runtimeContainerFactory.Container.Resolve().ShouldEqual(mock.Object); } } } diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index c4ecdce7..cbf3b688 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -45,7 +45,8 @@ Properties\CommonVersionInfo.cs - + + diff --git a/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs index f5ede929..949ebb78 100644 --- a/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs @@ -21,7 +21,7 @@ public class TheInitializeMethod { private Mock _mockLogger = new Mock(); private ScriptServices _scriptServices = new ScriptServices(null, null, null, null,null,null,null,null,null,null); - private Mock _mockFactory = new Mock(); + private Mock _mockFactory = new Mock(); private ScriptRuntime _runtime = null; public TheInitializeMethod() @@ -30,7 +30,7 @@ public TheInitializeMethod() builder.RegisterInstance(_mockLogger.Object); builder.RegisterInstance(_scriptServices); var container = builder.Build(); - _mockFactory.SetupGet(f => f.RuntimeContainer).Returns(container); + _mockFactory.SetupGet(f => f.Container).Returns(container); _runtime = new ScriptRuntime(_mockFactory.Object); } From bd75859f12ed696069f427a56533e4474c373986 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 26 Jul 2013 02:12:38 -0500 Subject: [PATCH 0367/1224] fixing references in scriptcs proj to be nuget references --- src/ScriptCs/ScriptCs.csproj | 59 ++++++++++++++++++++++-------------- src/ScriptCs/packages.config | 9 +++++- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index ccf0792c..6bd5f068 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -36,26 +36,57 @@ False ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.Configuration.dll - + + False ..\..\packages\Autofac.Mef.3.0.1\lib\net40\Autofac.Integration.Mef.dll - + + False ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll - + + False ..\..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll False ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll + + False + ..\..\packages\NuGet.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll - + + True + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + + + True + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + + + False + ..\..\packages\ScriptCs.Contracts.0.6.0-alpha\lib\net45\ScriptCs.Contracts.dll + + False - ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll + ..\..\packages\ScriptCs.Core.0.6.0-alpha\lib\net45\ScriptCs.Core.dll + + + False + ..\..\packages\ScriptCs.Engine.Roslyn.0.6.0-alpha\lib\net45\ScriptCs.Engine.Roslyn.dll + + + False + ..\..\packages\ScriptCs.Hosting.0.6.0-alpha\lib\net45\ScriptCs.Hosting.dll + + + False + ..\..\packages\ServiceStack.Text.3.9.56\lib\net35\ServiceStack.Text.dll @@ -108,24 +139,6 @@ Settings.Designer.cs - - - {9aef2d95-87fb-4829-b384-34bfe076d531} - ScriptCs.Hosting - - - {6049e205-8b5f-4080-b023-70600e51fd64} - ScriptCs.Contracts - - - {e590e710-e159-48e6-a3e6-1a83d3fe732c} - ScriptCs.Core - - - {e79ec231-e27d-4057-91c9-2d001a3a8c3b} - ScriptCs.Engine.Roslyn - - Properties\Icon.ico diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index 9531ddb6..5bf002f1 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -5,6 +5,13 @@ + - + + + + + + + \ No newline at end of file From 4d6ffb9633e6e6e897c293046f00071800b28c38 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 26 Jul 2013 15:13:13 -0500 Subject: [PATCH 0368/1224] Refactor IInitializationContainerFactory TODO: Better name --- .../InitializationContainerFactory.cs | 22 ++++++++++++++++++- src/ScriptCs.Core/RuntimeContainerFactory.cs | 10 +++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/ScriptCs.Core/InitializationContainerFactory.cs b/src/ScriptCs.Core/InitializationContainerFactory.cs index 5991e486..d3dbbc4e 100644 --- a/src/ScriptCs.Core/InitializationContainerFactory.cs +++ b/src/ScriptCs.Core/InitializationContainerFactory.cs @@ -11,7 +11,8 @@ namespace ScriptCs { public interface IInitializationContainerFactory { - IContainer Container { get; } + IAssemblyResolver GetAssemblyResolver(); + void RegisterServices(ContainerBuilder builder); } public class InitializationContainerFactory : ScriptContainerFactory, IInitializationContainerFactory @@ -21,6 +22,8 @@ public InitializationContainerFactory(ILog logger, IDictionary ove { } + + protected override IContainer CreateContainer() { var builder = new ContainerBuilder(); @@ -32,5 +35,22 @@ protected override IContainer CreateContainer() RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); return builder.Build(); } + + public IAssemblyResolver GetAssemblyResolver() + { + return Container.Resolve(); + } + + public void RegisterServices(ContainerBuilder builder) + { + var initializationContainer = Container; + + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + + } } } diff --git a/src/ScriptCs.Core/RuntimeContainerFactory.cs b/src/ScriptCs.Core/RuntimeContainerFactory.cs index 81d6d961..eaa5cc26 100644 --- a/src/ScriptCs.Core/RuntimeContainerFactory.cs +++ b/src/ScriptCs.Core/RuntimeContainerFactory.cs @@ -46,14 +46,10 @@ protected override IContainer CreateContainer() RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); RegisterOverrideOrDefault(builder, b => b.RegisterType().SingleInstance()); - var initializationContainer = _initializationContainerFactory.Container; - var assemblyResolver = initializationContainer.Resolve(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(assemblyResolver).As(); + _initializationContainerFactory.RegisterServices(builder); + + var assemblyResolver = _initializationContainerFactory.GetAssemblyResolver(); if (_initDirectoryCatalog) { From 9b2256c12bf5572504cacb8d6733057a326c0378 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 27 Jul 2013 18:06:25 -0400 Subject: [PATCH 0369/1224] Update NuGet from v2.2.1 to v2.6.1 --- .nuget/NuGet.exe | Bin 651264 -> 777728 bytes .nuget/NuGet.targets | 30 ++++++------------------------ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/.nuget/NuGet.exe b/.nuget/NuGet.exe index 4645f4b35e8ebd8508fe5691df73ce88a4a8028a..c296edf177fc5c0373b2c705a006b8c686098e37 100644 GIT binary patch literal 777728 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≷IF>|OB^!m|k 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�U$(s8uK5CNLY|i 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 `zWs> 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