8000 Merge pull request #267 from filipw/feature/follow-loads · dotnet-script/dotnet-script@a76a0f0 · GitHub
[go: up one dir, main page]

Skip to content

Commit a76a0f0

Browse files
authored
Merge pull request #267 from filipw/feature/follow-loads
Feature/follow loads
2 parents ad33be6 + 5b7e9fc commit a76a0f0

File tree

11 files changed

+224
-23
lines changed

11 files changed

+224
-23
lines changed

src/Dotnet.Script.Core/ScriptCompiler.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Runtime.InteropServices;
77
using System.Threading.Tasks;
88
using Dotnet.Script.Core.Internal;
9+
using Dotnet.Script.DependencyModel.Context;
910
using Dotnet.Script.DependencyModel.Environment;
1011
using Dotnet.Script.DependencyModel.NuGet;
1112
using Dotnet.Script.DependencyModel.Runtime;
@@ -83,10 +84,9 @@ public virtual ScriptOptions CreateScriptOptions(ScriptContext context, IList<Ru
8384
public virtual ScriptCompilationContext<TReturn> CreateCompilationContext<TReturn, THost>(ScriptContext context)
8485
{
8586
if (context == null) throw new ArgumentNullException(nameof(context));
86-
87-
Logger.Verbose($"Current runtime is '{RuntimeHelper.GetPlatformIdentifier()}'.");
8887

89-
var runtimeDependencies = RuntimeDependencyResolver.GetDependencies(context.WorkingDirectory, context.ScriptMode, context.Code.ToString()).ToArray();
88+
Logger.Verbose($"Current runtime is '{RuntimeHelper.GetPlatformIdentifier()}'.");
89+
RuntimeDependency[] runtimeDependencies = GetRuntimeDependencies(context);
9090

9191
var scriptOptions = CreateScriptOptions(context, runtimeDependencies.ToList());
9292

@@ -114,6 +114,18 @@ public virtual ScriptCompilationContext<TReturn> CreateCompilationContext<TRetur
114114
return new ScriptCompilationContext<TReturn>(script, context.Code, loader, scriptOptions);
115115
}
116116

117+
private RuntimeDependency[] GetRuntimeDependencies(ScriptContext context)
118+
{
119+
if (context.ScriptMode == ScriptMode.Script)
120+
{
121+
return RuntimeDependencyResolver.GetDependencies(context.FilePath).ToArray();
122+
}
123+
else
124+
{
125+
return RuntimeDependencyResolver.GetDependencies(context.WorkingDirectory, context.ScriptMode, context.Code.ToString()).ToArray();
126+
}
127+
}
128+
117129
private static void LoadNativeAssets(RuntimeDependency[] runtimeDependencies)
118130
{
119131
foreach (var nativeAsset in runtimeDependencies.SelectMany(rtd => rtd.NativeAssets).Distinct())
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
6+
namespace Dotnet.Script.DependencyModel.ProjectSystem
7+
{
8+
public static class FileUtils
9+
{
10+
public static string ReadFile(string path)
11+
{
12+
using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
13+
{
14+
using (var reader = new StreamReader(fileStream))
15+
{
16+
return reader.ReadToEnd();
17+
}
18+
}
19+
}
20+
}
21+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text.RegularExpressions;
6+
7+
namespace Dotnet.Script.DependencyModel.ProjectSystem
8+
{
9+
public class ScriptFilesResolver
10+
{
11+
public HashSet<string> GetScriptFiles(string csxFile)
12+
{
13+
HashSet<string> result = new HashSet<string>();
14+
Process(csxFile, result);
15+
return result;
16+
}
17+
18+
private void Process(string csxFile, HashSet<string> result)
19+
{
20+
if (result.Add(csxFile))
21+
{
22+
var loadDirectives = GetLoadDirectives(csxFile);
23+
foreach (var loadDirective in loadDirectives)
24+
{
25+
string referencedScript;
26+
if (!Path.IsPathRooted(loadDirective))
27+
{
28+
referencedScript = Path.GetFullPath((new Uri(Path.Combine(Path.GetDirectoryName(csxFile), loadDirective))).LocalPath);
29+
}
30+
else
31+
{
32+
referencedScript = loadDirective;
33+
}
34+
35+
Process(referencedScript, result);
36+
}
37+
}
38+
}
39+
40+
private static string[] GetLoadDirectives(string csxFile)
41+
{
42+
var content = FileUtils.ReadFile(csxFile);
43+
var matches = Regex.Matches(content, @"^\s*#load\s*""\s*(.+)\s*""", RegexOptions.IgnoreCase | RegexOptions.Multiline);
44+
List<string> result = new List<string>();
45+
foreach (var match in matches.Cast<Match>())
46+
{
47+
var value = match.Groups[1].Value;
48+
if (value.StartsWith("nuget", StringComparison.InvariantCultureIgnoreCase))
49+
{
50+
continue;
51+
}
52+
result.Add(value);
53+
}
54+
55+
return result.ToArray();
56+
}
57+
}
58+
}

src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptParser.cs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public ParseResult ParseFromFiles(IEnumerable<string> csxFiles)
4444
foreach (var csxFile in csxFiles)
4545
{
4646
_logger.Debug($"Parsing {csxFile}");
47-
var fileContent = ReadFile(csxFile);
47+
var fileContent = FileUtils.ReadFile(csxFile);
4848
allPackageReferences.UnionWith(ReadPackageReferencesFromReferenceDirective(fileContent));
4949
allPackageReferences.UnionWith(ReadPackageReferencesFromLoadDirective(fileContent));
5050
string targetFramework = ReadTargetFramework(fileContent);
@@ -102,16 +102,5 @@ private static string ReadTargetFramework(string fileContent)
102102
}
103103
return null;
104104
}
105-
106-
private static string ReadFile(string pathToFile)
107-
{
108-
using (var fileStream = new FileStream(pathToFile, FileMode.Open))
109-
{
110-
using (var reader = new StreamReader(fileStream))
111-
{
112-
return reader.ReadToEnd();
113-
}
114-
}
115-
}
116105
}
117106
}

src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptProjectProvider.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ namespace Dotnet.Script.DependencyModel.ProjectSystem
99
public class ScriptProjectProvider
1010
{
1111
private readonly ScriptParser _scriptParser;
12-
12+
private readonly ScriptFilesResolver _scriptFilesResolver;
1313
private readonly Logger _logger;
1414

15-
private ScriptProjectProvider(ScriptParser scriptParser, LogFactory logFactory)
15+
private ScriptProjectProvider(ScriptParser scriptParser, ScriptFilesResolver scriptFilesResolver, LogFactory logFactory)
1616
{
1717
_logger = logFactory.CreateLogger<ScriptProjectProvider>();
1818
_scriptParser = scriptParser;
19+
_scriptFilesResolver = scriptFilesResolver;
1920
}
2021

21-
public ScriptProjectProvider(LogFactory logFactory) : this(new ScriptParser(logFactory), logFactory)
22+
public ScriptProjectProvider(LogFactory logFactory) : this(new ScriptParser(logFactory), new ScriptFilesResolver(), logFactory)
2223
{
2324
}
2425

@@ -60,12 +61,24 @@ public string CreateProject(string targetDirectory, string defaultTargetFramewor
6061
return null;
6162
}
6263

63-
_logger.Debug($"Creating project file for *.csx files found in {targetDirectory} using {defaultTargetFramework} as the default framework." );
64-
64+
_logger.Debug($"Creating project file for *.csx files found in {targetDirectory} using {defaultTargetFramework} as the default framework.");
65+
6566
var csxFiles = Directory.GetFiles(targetDirectory, "*.csx", SearchOption.AllDirectories);
67+
return CreateProjectFileFromScriptFiles(targetDirectory, defaultTargetFramework, csxFiles);
68+
}
69+
70+
public string CreateProjectForScriptFile(string scriptFile)
71+
{
72+
_logger.Debug($"Creating project file for {scriptFile}");
73+
var scriptFiles = _scriptFilesResolver.GetScriptFiles(scriptFile);
74+
return CreateProjectFileFromScriptFiles(Path.GetDirectoryName(scriptFile), RuntimeHelper.TargetFramework, scriptFiles.ToArray());
75+
}
76+
77+
private string CreateProjectFileFromScriptFiles(string targetDirectory, string defaultTargetFramework, string[] csxFiles)
78+
{
6679
var parseresult = _scriptParser.ParseFromFiles(csxFiles);
6780

68-
pathToProjectFile = GetPathToProjectFile(targetDirectory);
81+
var pathToProjectFile = GetPathToProjectFile(targetDirectory);
6982
var projectFile = new ProjectFile();
7083

7184
foreach (var packageReference in parseresult.PackageReferences)

src/Dotnet.Script.DependencyModel/Runtime/RuntimeDependencyResolver.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ public IEnumerable<RuntimeDependency> GetDependencies(string targetDirectory, Sc
5454
return GetDependenciesInternal(pathToProjectFile);
5555
}
5656

57+
public IEnumerable<RuntimeDependency> GetDependencies(string scriptFile)
58+
{
59+
var pathToProjectFile = _scriptProjectProvider.CreateProjectForScriptFile(scriptFile);
60+
return GetDependenciesInternal(pathToProjectFile);
61+
}
62+
5763
private IEnumerable<RuntimeDependency> GetDependenciesInternal(string pathToProjectFile)
5864
{
5965
var dependencyInfo = _scriptDependencyInfoProvider.GetDependencyInfo(pathToProjectFile);

src/Dotnet.Script.Tests/InteractiveRunnerTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Text;
88
using System;
99
using Microsoft.CodeAnalysis.Text;
10+
using Dotnet.Script.DependencyModel.Context;
1011

1112
namespace Dotnet.Script.Tests
1213
{
@@ -93,7 +94,7 @@ public async Task ValueFromSeededFile()
9394
};
9495

9596
var ctx = GetRunner(commands);
96-
await ctx.Runner.RunLoopWithSeed(new ScriptContext(SourceText.From(@"var x = 1;"), Directory.GetCurrentDirectory(), new string[0]));
97+
await ctx.Runner.RunLoopWithSeed(new ScriptContext(SourceText.From(@"var x = 1;"), Directory.GetCurrentDirectory(), new string[0], scriptMode:ScriptMode.REPL));
9798

9899
var result = ctx.Console.Out.ToString();
99100
Assert.Contains("2", result);
@@ -110,7 +111,7 @@ public async Task RuntimeExceptionFromSeededFile()
110111
};
111112

112113
var ctx = GetRunner(commands);
113-
await ctx.Runner.RunLoopWithSeed(new ScriptContext(SourceText.From(@"throw new Exception(""die!"");"), Directory.GetCurrentDirectory(), new string[0]));
114+
await ctx.Runner.RunLoopWithSeed(new ScriptContext(SourceText.From(@"throw new Exception(""die!"");"), Directory.GetCurrentDirectory(), new string[0], scriptMode:ScriptMode.REPL));
114115

115116
var errorResult = ctx.Console.Error.ToString();
116117
var result = ctx.Console.Out.ToString();

src/Dotnet.Script.Tests/ScriptExecutionTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ public static void ShouldHandleIssue181()
119119
Assert.Contains("42", result.output);
120120
}
121121

122+
[Fact]
123+
public static void ShouldHandleIssue189()
124+
{
125+
var result = Execute(Path.Combine("Issue189","SomeFolder","Script.csx"));
126+
Assert.Contains("Newtonsoft.Json.JsonConvert", result.output);
127+
}
128+
122129
[Fact]
123130
public static void ShouldHandleIssue198()
124131
{
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System.IO;
2+
using Xunit;
3+
using Dotnet.Script.DependencyModel.ProjectSystem;
4+
5+
namespace Dotnet.Script.Tests
6+
{
7+
public class ScriptFilesResolverTests
8+
{
9+
[Fact]
10+
public void ShouldOnlyResolveRootScript()
11+
{
12+
using (var rootFolder = new DisposableFolder())
13+
{
14+
var rootScript = WriteScript(string.Empty, rootFolder.Path, "Foo.csx");
15+
WriteScript(string.Empty, rootFolder.Path, "Bar.csx");
16+
var scriptFilesResolver = new ScriptFilesResolver();
17+
18+
var files = scriptFilesResolver.GetScriptFiles(rootScript);
19+
20+
Assert.True(files.Count == 1);
21+
Assert.Contains(files, f => f.Contains("Foo.csx"));
22+
Assert.Contains(files, f => !f.Contains("Bar.csx"));
23+
}
24+
}
25+
[Fact]
26+
public void ShouldResolveLoadedScriptInRootFolder()
27+
{
28+
using (var rootFolder = new DisposableFolder())
29+
{
30+
var rootScript = WriteScript("#load \"Bar.csx\"", rootFolder.Path, "Foo.csx");
31+
WriteScript(string.Empty, rootFolder.Path, "Bar.csx");
32+
var scriptFilesResolver = new ScriptFilesResolver();
33+
34+
var files = scriptFilesResolver.GetScriptFiles(rootScript);
35+
36+
Assert.True(files.Count == 2);
37+
Assert.Contains(files, f => f.Contains("Foo.csx"));
38+
Assert.Contains(files, f => f.Contains("Bar.csx"));
39+
}
40+
}
41+
42+
[Fact]
43+
public void ShouldResolveLoadedScriptInSubFolder()
44+
{
45+
using (var rootFolder = new DisposableFolder())
46+
{
47+
var rootScript = WriteScript("#load \"SubFolder/Bar.csx\"", rootFolder.Path, "Foo.csx");
48+
var subFolder = Path.Combine(rootFolder.Path, "SubFolder");
49+
Directory.CreateDirectory(subFolder);
50+
WriteScript(string.Empty, subFolder, "Bar.csx");
51+
52+
var scriptFilesResolver = new ScriptFilesResolver();
53+
var files = scriptFilesResolver.GetScriptFiles(rootScript);
54+
55+
Assert.True(files.Count == 2);
56+
Assert.Contains(files, f => f.Contains("Foo.csx"));
57+
Assert.Contains(files, f => f.Contains("Bar.csx"));
58+
}
59+
}
60+
61+
[Fact]
62+
public void ShouldResolveLoadedScriptWithRootPath()
63+
{
64+
using (var rootFolder = new DisposableFolder())
65+
{
66+
var subFolder = Path.Combine(rootFolder.Path, "SubFolder");
67+
Directory.CreateDirectory(subFolder);
68+
var fullPathToBarScript = WriteScript(string.Empty, subFolder, "Bar.csx");
69+
var rootScript = WriteScript($"#load \"{fullPathToBarScript}\"", rootFolder.Path, "Foo.csx");
70+
71+
72+
var scriptFilesResolver = new ScriptFilesResolver();
73+
var files = scriptFilesResolver.GetScriptFiles(rootScript);
74+
75+
Assert.True(files.Count == 2);
76+
Assert.Contains(files, f => f.Contains("Foo.csx"));
77+
Assert.Contains(files, f => f.Contains("Bar.csx"));
78+
}
79+
}
80+
81+
82+
private static string WriteScript(string content, string folder, string name)
83+
{
84+
var fullPath = Path.Combine(folder, name);
85+
File.WriteAllText(Path.Combine(folder, name), content);
86+
return fullPath;
87+
88+
}
89+
}
90+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#r "nuget: Newtonsoft.Json,10.0.3"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#load "../AnotherFolder/Dependencies.csx"
2+
using Newtonsoft.Json;
3+
Console.WriteLine(typeof(JsonConvert));

0 commit comments

Comments
 (0)
0