Skip to content

Commit

Permalink
fixup! Decouple dotnet-ef from the framework
Browse files Browse the repository at this point in the history
Rename things
  • Loading branch information
bricelam committed Apr 5, 2016
1 parent aeb8775 commit 83e510f
Show file tree
Hide file tree
Showing 20 changed files with 103 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

namespace Microsoft.EntityFrameworkCore.Design
{
/// <summary>
/// Represents an exception whose stack trace should, by default, not be reported by the commands.
/// </summary>
public class OperationException : Exception
{
public OperationException([NotNull] string message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

namespace Microsoft.EntityFrameworkCore.Design
{
/// <summary>
/// A version-resilient, AppDomain-and-reflection-friendly facade for command operations.
/// </summary>
public partial class OperationExecutor
{
private readonly LazyRef<DbContextOperations> _contextOperations;
Expand Down Expand Up @@ -124,7 +127,7 @@ public AddMigration(
}
}

private IEnumerable<string> AddMigrationImpl(
private IDictionary AddMigrationImpl(
[NotNull] string name,
[CanBeNull] string outputDir,
[CanBeNull] string contextType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function Use-DbContext {
if ($candidates.length -gt 1 -and $exactMatch -is "String") {
$candidates = $exactMatch
}

if ($candidates.length -lt 1) {
throw "No DbContext named '$Context' was found"
} elseif ($candidates.length -gt 1 -and !($candidates -is "String")) {
Expand Down Expand Up @@ -500,7 +500,7 @@ function Scaffold-DbContext {

$artifacts | %{ $dteProject.ProjectItems.AddFromFile($_) | Out-Null }
$DTE.ItemOperations.OpenFile($artifacts[0]) | Out-Null

ShowConsole
}
}
Expand Down Expand Up @@ -537,7 +537,7 @@ function GetContextTypes($projectName, $startupProjectName, $environment) {
$project = $values.Project

if (IsDotNetProject $startupProject) {
$types = InvokeDotNetEf $startupProject -Json dbcontext list
$types = InvokeDotNetEf $startupProject -Json dbcontext list
return $types | %{ $_.fullName }
} else {
$contextTypes = InvokeOperation $startupProject $environment $project GetContextTypes -skipBuild
Expand Down Expand Up @@ -642,7 +642,7 @@ function InvokeDotNetEf($project, [switch] $Json) {
$arguments += "--json"
} else {
# TODO better json output parsing so we don't need to suppress verbose output
$arguments = ,"--verbose" + $arguments
$arguments = ,"--verbose" + $arguments
}
$command = "ef $($arguments -join ' ')"
try {
Expand Down
16 changes: 0 additions & 16 deletions src/dotnet-ef/CommandException.cs

This file was deleted.

2 changes: 1 addition & 1 deletion src/dotnet-ef/DatabaseDropCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static void Configure([NotNull] CommandLineApplication command)

private static int Execute(string context, string startupProject, string environment, bool isForced)
{
new OperationExecutor(startupProject, environment)
new ReflectionOperationExecutor(startupProject, environment)
.DropDatabase(
context,
(database, dataSource) =>
Expand Down
2 changes: 1 addition & 1 deletion src/dotnet-ef/DatabaseUpdateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static void Configure([NotNull] CommandLineApplication command)

private static int Execute(string migration, string context, string startupProject, string environment)
{
new OperationExecutor(startupProject, environment)
new ReflectionOperationExecutor(startupProject, environment)
.UpdateDatabase(migration, context);

return 0;
Expand Down
2 changes: 1 addition & 1 deletion src/dotnet-ef/DbContextListCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private static int Execute(
string environment,
Action<IEnumerable<IDictionary>> reportResultsAction)
{
var contextTypes = new OperationExecutor(startupProject, environment)
var contextTypes = new ReflectionOperationExecutor(startupProject, environment)
.GetContextTypes();

reportResultsAction(contextTypes);
Expand Down
2 changes: 1 addition & 1 deletion src/dotnet-ef/DbContextScaffoldCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private static int Execute(
string startupProject,
string environment)
{
new OperationExecutor(startupProject, environment)
new ReflectionOperationExecutor(startupProject, environment)
.ReverseEngineer(
provider,
connection,
Expand Down
4 changes: 2 additions & 2 deletions src/dotnet-ef/MigrationsAddCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ private static int Execute(
string environment,
Action<IDictionary> reporter)
{
var files = new OperationExecutor(startupProject, environment)
var files = new ReflectionOperationExecutor(startupProject, environment)
.AddMigration(name, outputDir, context);

reporter?.Invoke(files);
Expand All @@ -79,7 +79,7 @@ private static void ReportJson(IDictionary files)
{
// TODO use a real json serializer
Reporter.Output.WriteLine("{");
Reporter.Output.WriteLine(" \"MigrationFile\": \""+ SerializePath(files["MigrationFile"] as string) + "\",");
Reporter.Output.WriteLine(" \"MigrationFile\": \"" + SerializePath(files["MigrationFile"] as string) + "\",");
Reporter.Output.WriteLine(" \"MetadataFile\": \"" + SerializePath(files["MetadataFile"] as string) + "\",");
Reporter.Output.WriteLine(" \"SnapshotFile\": \"" + SerializePath(files["SnapshotFile"] as string) + "\"");
Reporter.Output.WriteLine("}");
Expand Down
2 changes: 1 addition & 1 deletion src/dotnet-ef/MigrationsListCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private static int Execute(
string environment,
Action<IEnumerable<IDictionary>> reportResultsAction)
{
var migrations = new OperationExecutor(startupProject, environment)
var migrations = new ReflectionOperationExecutor(startupProject, environment)
.GetMigrations(context);

reportResultsAction(migrations);
Expand Down
2 changes: 1 addition & 1 deletion src/dotnet-ef/MigrationsRemoveCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static void Configure([NotNull] CommandLineApplication command)

private static int Execute(string context, string startupProject, string environment, bool force)
{
new OperationExecutor(startupProject, environment)
new ReflectionOperationExecutor(startupProject, environment)
.RemoveMigration(context, force);

return 0;
Expand Down
2 changes: 1 addition & 1 deletion src/dotnet-ef/MigrationsScriptCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private static int Execute(
string startupProject,
string environment)
{
var sql = new OperationExecutor(startupProject, environment)
var sql = new ReflectionOperationExecutor(startupProject, environment)
.ScriptMigration(from, to, idempotent, context);

if (string.IsNullOrEmpty(output))
Expand Down
33 changes: 33 additions & 0 deletions src/dotnet-ef/OperationErrorException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using JetBrains.Annotations;

namespace Microsoft.EntityFrameworkCore.Commands
{
public class OperationErrorException : Exception
{
public const string OperationException = "Microsoft.EntityFrameworkCore.Design.OperationException";

private readonly string _stackTrace;

public OperationErrorException([NotNull] string type, [NotNull] string stackTrace, [NotNull] string message)
: base(message)
{
_stackTrace = stackTrace;
Type = type;
}

public virtual string Type { get; }

public override string ToString()
=> _stackTrace;

public static OperationErrorException CreateOperationException([NotNull] string message)
=> new OperationErrorException(
OperationException,
OperationException + ": " + message + Environment.NewLine + Environment.StackTrace,
message);
}
}
3 changes: 1 addition & 2 deletions src/dotnet-ef/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ public static int Main([NotNull] string[] args)
ex = ex.InnerException;
}

if (!(ex is CommandException
|| (ex as OperationException)?.Type == "Microsoft.EntityFrameworkCore.Design.OperationException"))
if ((ex as OperationErrorException)?.Type != OperationErrorException.OperationException)
{
Reporter.Error.WriteLine(ex.ToString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,16 @@

namespace Microsoft.EntityFrameworkCore.Commands
{
public class OperationExecutor
public class ReflectionOperationExecutor
{
private const string ExecutorTypeName = "Microsoft.EntityFrameworkCore.Design.OperationExecutor";
private const string DataDirEnvName = "ADONET_DATA_DIR";

private readonly Assembly _commandsAssembly;
private readonly object _executor;
private readonly string _startupProjectDir;

private const string DataDirEnvName = "ADONET_DATA_DIR";
private const string DefaultConfiguration = "Debug";

public OperationExecutor([CanBeNull] string startupProject, [CanBeNull] string environment)
public ReflectionOperationExecutor([CanBeNull] string startupProject, [CanBeNull] string environment)
{
var project = Path.Combine(Directory.GetCurrentDirectory(), Project.FileName);

Expand All @@ -52,12 +50,12 @@ public OperationExecutor([CanBeNull] string startupProject, [CanBeNull] string e
new[] { startupProject, "-f", startupProjectContext.TargetFramework.GetShortFolderName() });
if (buildCommand.Execute().ExitCode != 0)
{
throw new CommandException("Build failed.");
throw OperationErrorException.CreateOperationException("Build failed.");
}

Reporter.Verbose.WriteLine("Build succeeded.".Bold().Black());

var runtimeOutputPath = startupProjectContext.GetOutputPaths(DefaultConfiguration)?.RuntimeOutputPath;
var runtimeOutputPath = startupProjectContext.GetOutputPaths(Constants.DefaultConfiguration)?.RuntimeOutputPath;
if (!string.IsNullOrEmpty(runtimeOutputPath))
{
// TODO set data directory in AppDomain when/if this supports desktop .NET
Expand All @@ -72,8 +70,19 @@ public OperationExecutor([CanBeNull] string startupProject, [CanBeNull] string e
var rootNamespace = projectFile.Name;
var assemblyLoadContext = startupProjectContext.CreateLoadContext();

_commandsAssembly = assemblyLoadContext.LoadFromAssemblyName(
new AssemblyName("Microsoft.EntityFrameworkCore.Commands"));
try
{
_commandsAssembly = assemblyLoadContext.LoadFromAssemblyName(
new AssemblyName("Microsoft.EntityFrameworkCore.Commands"));
}
catch (FileNotFoundException ex)
{
Reporter.Verbose.WriteLine(ex.ToString().Bold().Black());

throw OperationErrorException.CreateOperationException(
"Cannot execute this command because Microsoft.EntityFramework.Commands is not installed in the " +
"startup project '" + startupAssemblyName + "'.");
}

var assemblyLoader = Activator.CreateInstance(
_commandsAssembly.GetType(
Expand All @@ -97,11 +106,12 @@ public OperationExecutor([CanBeNull] string startupProject, [CanBeNull] string e
_commandsAssembly.GetType(ExecutorTypeName, throwOnError: true, ignoreCase: false),
logHandler,
new Dictionary<string, string>
{
{
["targetName"] = assemblyName,
["startupTargetName"] = startupAssemblyName,
["environment"] = environment,
["projectDir"] = projectDir,
["startupProjectDir"] = _startupProjectDir,
["rootNamespace"] = rootNamespace
},
assemblyLoader);
Expand Down Expand Up @@ -216,8 +226,8 @@ private ProjectContext GetCompatibleProjectContext(string projectPath)
f => new NuGetFramework(f));
if (framework == null)
{
throw new CommandException(
"The project '" + projectFile.Name + "' doesn't target a framework compatible with .NET Standard "+
throw OperationErrorException.CreateOperationException(
"The project '" + projectFile.Name + "' doesn't target a framework compatible with .NET Standard " +
"App 1.5. You must target a compatible framework such as 'netstandard1.3' in order to use the " +
"Entity Framework .NET Core CLI Commands.");
}
Expand Down Expand Up @@ -260,7 +270,7 @@ private T Execute<T>(string operation, IDictionary args)

if (resultHandler.ErrorType != null)
{
throw new OperationException(
throw new OperationErrorException(
resultHandler.ErrorType,
resultHandler.ErrorStackTrace,
resultHandler.ErrorMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ public void GetContextType_works_cross_domain()
public void AddMigration_works_cross_domain()
{
var artifacts = _project.Executor.AddMigration("EmptyMigration", "Migrationz", "SimpleContext");
Assert.Equal(3, artifacts.Count());
Assert.NotNull(artifacts);
Assert.NotNull(artifacts["MigrationFile"]);
Assert.NotNull(artifacts["MetadataFile"]);
Assert.NotNull(artifacts["SnapshotFile"]);
Assert.True(Directory.Exists(Path.Combine(_project.TargetDir, @"Migrationz")));
}

Expand Down Expand Up @@ -124,12 +127,12 @@ protected override void Up(MigrationBuilder migrationBuilder)
}" }
};
var build = source.Build();
Executor = new OperationExecutorWrapper(TargetDir, build.TargetName, TargetDir, TargetDir, "SimpleProject");
Executor = new AppDomainOperationExecutor(TargetDir, build.TargetName, TargetDir, TargetDir, "SimpleProject");
}

public string TargetDir => _directory.Path;

public OperationExecutorWrapper Executor { get; }
public AppDomainOperationExecutor Executor { get; }

public void Dispose()
{
Expand Down Expand Up @@ -219,7 +222,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
}" }
};
var build = source.Build();
using (var executor = new OperationExecutorWrapper(targetDir, build.TargetName, targetDir, targetDir, "MyProject"))
using (var executor = new AppDomainOperationExecutor(targetDir, build.TargetName, targetDir, targetDir, "MyProject"))
{
var migrations = executor.GetMigrations("Context1");

Expand Down Expand Up @@ -320,7 +323,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
}" }
};
var migrationsBuild = migrationsSource.Build();
using (var executor = new OperationExecutorWrapper(targetDir, migrationsBuild.TargetName, targetDir, targetDir, "MyProject"))
using (var executor = new AppDomainOperationExecutor(targetDir, migrationsBuild.TargetName, targetDir, targetDir, "MyProject"))
{
var contextTypes = executor.GetContextTypes();

Expand Down Expand Up @@ -398,10 +401,10 @@ protected override void Up(MigrationBuilder migrationBuilder)
}" }
};
var build = source.Build();
using (var executor = new OperationExecutorWrapper(targetDir, build.TargetName, targetDir, targetDir, "MyProject"))
using (var executor = new AppDomainOperationExecutor(targetDir, build.TargetName, targetDir, targetDir, "MyProject"))
{
var artifacts = executor.AddMigration("MyMigration", /*outputDir:*/ null, "MySecondContext");
Assert.Equal(3, artifacts.Count());
Assert.Equal(3, artifacts.Keys.Count);
Assert.True(Directory.Exists(Path.Combine(targetDir, @"Migrations\MySecond")));
}
}
Expand Down Expand Up @@ -471,9 +474,9 @@ protected override void Up(MigrationBuilder migrationBuilder)
}" }
};
var build = source.Build();
using (var executor = new OperationExecutorWrapper(targetDir, build.TargetName, targetDir, targetDir, "MyProject"))
using (var executor = new AppDomainOperationExecutor(targetDir, build.TargetName, targetDir, targetDir, "MyProject"))
{
var ex = Assert.Throws<WrappedOperationException>(
var ex = Assert.Throws<OperationErrorException>(
() => executor.GetMigrations("MyContext"));

Assert.Equal(
Expand All @@ -487,9 +490,9 @@ protected override void Up(MigrationBuilder migrationBuilder)
public void Assembly_load_errors_are_wrapped()
{
var targetDir = AppDomain.CurrentDomain.BaseDirectory;
using (var executor = new OperationExecutorWrapper(targetDir, "Unknown", targetDir, targetDir, "Unknown"))
using (var executor = new AppDomainOperationExecutor(targetDir, "Unknown", targetDir, targetDir, "Unknown"))
{
Assert.Throws<WrappedOperationException>(() => executor.GetContextTypes());
Assert.Throws<OperationErrorException>(() => executor.GetContextTypes());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
<Compile Include="Migrations\CodeCompilationTest.cs" />
<Compile Include="Migrations\ModelSnapshotTest.cs" />
<Compile Include="Migrations\OperationCompilationTest.cs" />
<Compile Include="TestUtilities\OperationExecutorWrapper.cs" />
<Compile Include="TestUtilities\AppDomainOperationExecutor.cs" />
<Compile Include="TestUtilities\TempDirectory.cs" />
<Compile Include="TestUtilities\WrappedOperationException.cs" />
</ItemGroup>
Expand Down
Loading

0 comments on commit 83e510f

Please sign in to comment.