Skip to content

Commit

Permalink
Nothing to be proud of here but at least it runs at least one netcore…
Browse files Browse the repository at this point in the history
…2.0 suite using System.Data.SqlClient (which requires native dll loading).
  • Loading branch information
Tobbe Gyllebring committed Jul 10, 2018
1 parent f4ecc08 commit 171f390
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Source/Cone/AssemblyMethods.cs
@@ -1,4 +1,4 @@
using System;
using System;
using System.Reflection;

namespace Cone
Expand Down
6 changes: 6 additions & 0 deletions Source/Cone/Cone.csproj
Expand Up @@ -18,4 +18,10 @@
<Version>4.3.0</Version>
</PackageReference>
</ItemGroup>

<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>C:\Program Files\dotnet\sdk\NuGetFallbackFolder\newtonsoft.json\9.0.1\lib\netstandard1.0\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
206 changes: 206 additions & 0 deletions Source/Cone/Core/AssemblyLoader.cs
@@ -0,0 +1,206 @@
using System;
using System.Reflection;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using System.Linq;

namespace Cone.Core
{


#if NET45
static class AssemblyLoader
{
public static Assembly LoadFrom(string path) {
Console.WriteLine($"Loading {path}");
return Assembly.LoadFrom(path);
}
}
#else
using System.Runtime.Loader;

public struct DependencyPath
{
public string Path;
public bool IsManaged;
}

public static class AssemblyLoader
{
public static IEnumerable<DependencyPath> Resolve(AssemblyJsonDeps deps, RuntimeDep runtime, string depName, HashSet<string> seen) {
if(!seen.Add(depName))
yield break;

if(!deps.TryGetLibraryDep(depName, out var found))
yield break;
string foundDep = null;
var depIsManaged = true;

foreach(var probePath in runtime.PackageProbePaths) {
var managedPath = $@"{probePath}\{found.path}\runtimes\{runtime.OS}\lib\{runtime.FrameworkVersion}";
if (Directory.Exists(managedPath)) {
foundDep = managedPath;
depIsManaged = true;
} else {
var nativepath = $@"{probePath}\{found.path}\runtimes\{runtime.OS}-{runtime.Arch}\native";
if (Directory.Exists(nativepath)) {
foundDep = nativepath;
depIsManaged = false;
}
}
}

/*
var foundDep = runtime.PackageProbePaths
.Select(x => {
if(found.path.StartsWith("runtime."))
return new DependencyPath { Path = Path.Combine(x, found.path, "runtimes", $"{runtime.OS}-{runtime.Arch}", "native"), IsManaged = false };
else
return new DependencyPath { Path = Path.Combine(x, found.path, "runtimes", runtime.OS, "lib", runtime.FrameworkVersion), IsManaged = true };
})
.FirstOrDefault(x => Directory.Exists(x.Path));
*/
if (foundDep != null)
foreach(var item in Directory.GetFiles(foundDep))
yield return new DependencyPath { Path = item, IsManaged = depIsManaged };

var childDeps = deps.DepsFor(found.FullKey).ToList();
//foreach(var item in childDeps)
// Console.WriteLine($"Resolving {item} for {depName}");

foreach(var child in childDeps)
foreach(var item in Resolve(deps, runtime, child.Split('/')[0], seen))
yield return item;
}

static AssemblyJsonDeps Deps;

class ConeLoadContext : AssemblyLoadContext
{
public void LoadNativeDll(string path) => LoadUnmanagedDllFromPath(path);

protected override Assembly Load(AssemblyName assemblyName) => Default.LoadFromAssemblyName(assemblyName);
}


public static Assembly LoadFrom(string path) {
var result = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
if(Deps == null) {
Deps = AssemblyJsonDeps.LoadFrom(path);
var seen = new HashSet<string>();
var dlls = new ConeLoadContext();
AssemblyLoadContext.Default.Resolving += (_, e) => {
//WriteDiagnostic($"Resolving {e.Name}");
foreach(var item in Resolve(Deps, new RuntimeDep {
OS = Environment.GetEnvironmentVariable("CONE_OS") ?? "win",
Arch = Environment.Is64BitProcess ? "x64" : "x86",
//FrameworkVersion = "netstandard2.0",
FrameworkVersion = Environment.GetEnvironmentVariable("CONE_TARGET_FRAMEWORK"),
PackageProbePaths = AppContext.GetData("PROBING_DIRECTORIES").ToString().Split(new[]{ ';' }, StringSplitOptions.RemoveEmptyEntries),
}, e.Name, seen)) {
//WriteDiagnostic($" Loading Dependencty {item.Path} for {e.Name}");
if(item.IsManaged)
LoadFrom(item.Path);
else dlls.LoadNativeDll(item.Path);
}
return null;
};
}
return result;
}

static void WriteDiagnostic(string message) {
var fc = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine(message);
Console.ForegroundColor = fc;
}
}
#endif

public class AssemblyJsonDeps
{
const string DepsSuffix = "deps.json";

public class JsonDeps
{
public JsonDepsRuntimeTarget runtimeTarget;
public Dictionary<string, Dictionary<string, JsonTargetDep>> targets;
public Dictionary<string, JsonLibraryDep> libraries;
}

public class JsonDepsRuntimeTarget
{
public string name;
}

public class JsonTargetDep
{
public Dictionary<string, string> dependencies;
public Dictionary<string, JsonRuntime> runtime;
public Dictionary<string, JsonRuntimeTarget> runtimeTargets;
}

public class JsonRuntimeTarget
{
public string rid;
}

public class JsonRuntime
{
public string path;
}

public class JsonLibraryDep
{
public string FullKey;
public string type;
public bool servicable;
public string sha512;
public string path;
public string hashPath;
}

JsonDeps deps;

public bool TryGetLibraryDep(string key, out JsonLibraryDep found) {
foreach(var item in deps.libraries) {
if(item.Key.Split('/')[0] == key) {
found = item.Value;
found.FullKey = item.Key;
return true;
}
}
found = null;
return false;
}

public IEnumerable<string> DepsFor(string name) {
if(deps.targets[deps.runtimeTarget.name].TryGetValue(name, out var found) && found.dependencies != null) {
return found.dependencies.Select(x => x.Key);
} else
return Enumerable.Empty<string>();
}

public static AssemblyJsonDeps LoadFrom(string assemblyPath) {
var depsPath = Path.ChangeExtension(assemblyPath, DepsSuffix);
var result = new AssemblyJsonDeps();
if (File.Exists(depsPath)) {
result.deps = JsonConvert.DeserializeObject<JsonDeps>(File.ReadAllText(depsPath));
}
return result;
}

public override string ToString() => JsonConvert.SerializeObject(deps, Formatting.Indented);
}

public class RuntimeDep
{
public string OS;
public string Arch;
public string FrameworkVersion;
public string[] PackageProbePaths;
}

}
2 changes: 1 addition & 1 deletion Source/Cone/Platform/Runners/CrossDomainConeRuner.cs
Expand Up @@ -188,7 +188,7 @@ class RunTestsCommand
var testAssemblies = new List<Assembly>();
for(var i = 0; i != assemblyPaths.Length; ++i)
try {
testAssemblies.Add(Assembly.LoadFrom(Path.GetFullPath(assemblyPaths[i])));
testAssemblies.Add(AssemblyLoader.LoadFrom(Path.GetFullPath(assemblyPaths[i])));
}
catch (FileNotFoundException) {
logError("Failed to load: " + assemblyPaths[i]);
Expand Down
3 changes: 2 additions & 1 deletion Source/Cone/Runners/ConeResolver.cs
Expand Up @@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
using Cone.Core;

namespace Cone.Runners
{
Expand Down Expand Up @@ -37,7 +38,7 @@ struct ResolveCandidate

var found = Array.FindIndex(candidates, x => x.Name == name);
if(found != -1) {
return Assembly.LoadFrom(candidates[found].Path);
return AssemblyLoader.LoadFrom(candidates[found].Path);
}

return null;
Expand Down
13 changes: 2 additions & 11 deletions Source/Cone/Runners/ConesoleRunner.cs
Expand Up @@ -40,11 +40,11 @@ public class ConesoleRunner
foreach(var ext in new[] { ".dll", ".exe "}) {
var probeBin = Path.Combine(specBinPath, probeName + ext);
if(File.Exists(probeBin))
return Assembly.LoadFrom(probeBin);
return AssemblyLoader.LoadFrom(probeBin);
}
return null;
};
var assemblies = Array.ConvertAll(config.AssemblyPaths,AssemblyLoadFrom);
var assemblies = Array.ConvertAll(config.AssemblyPaths, AssemblyLoader.LoadFrom);
if (config.RunList == null)
runner.RunTests(results, assemblies);
else runner.RunTests(config.RunList, results, assemblies);
Expand All @@ -53,15 +53,6 @@ public class ConesoleRunner
return results.FailureCount;
}

static Assembly AssemblyLoadFrom(string path) {
#if NET45
return Assembly.LoadFrom(path);
#else
Console.WriteLine("Loading " + path);
return AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
#endif
}

static TestSession CreateTestSession(ISessionLogger logger, WorkerConfiguration config) {
return new TestSession(logger) {
IncludeSuite = config.IncludeSuite,
Expand Down
2 changes: 1 addition & 1 deletion Source/Cone/Runners/SimpleConeRunner.cs
Expand Up @@ -44,7 +44,7 @@ public SimpleConeRunner(ITestNamer testNamer): this(testNamer, new DefaultFixtur
Check.Initialize();
results.RunTests(CreateTestRun(
runList,
BuildFlatSuites(assemblies.SelectMany(x => x.GetExportedTypes()))
BuildFlatSuites(assemblies.SelectMany(AssemblyMethods.GetExportedTypes))
.SelectMany(x => x.Tests)));
}

Expand Down
11 changes: 7 additions & 4 deletions Source/dotnet-conesole/Program.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -90,10 +91,12 @@ static int RunConesole(string fxVersion, IEnumerable<string> args)
foreach(var (worker, isDll) in probePaths.Select(x => GetWorkerProbe(x, fxVersion))) {
if(!File.Exists(worker))
continue;
var conesole = Process.Start(new ProcessStartInfo {
FileName = isDll ? "dotnet" : worker,
Arguments = (isDll ? worker + " " : string.Empty) + string.Join(' ', args.Select(x => $"\"{x}\""))
});
var startInfo = new ProcessStartInfo {
FileName = isDll ? "dotnet" : worker,
Arguments = (isDll ? worker + " " : string.Empty) + string.Join(' ', args.Select(x => $"\"{x}\"")),
};
startInfo.Environment.Add("CONE_TARGET_FRAMEWORK", fxVersion);
var conesole = Process.Start(startInfo);
conesole.WaitForExit();
return conesole.ExitCode;
}
Expand Down

0 comments on commit 171f390

Please sign in to comment.