Skip to content

Commit ee8d832

Browse files
committed
Implement list migrations action
1 parent 9379167 commit ee8d832

30 files changed

+1158
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/.idea
2+
bin/
3+
obj/

Efmig.sln

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Efmig", "Efmig\Efmig.csproj", "{E5F1A017-F109-49A1-A356-028B3627200C}"
4+
EndProject
5+
Global
6+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7+
Debug|Any CPU = Debug|Any CPU
8+
Release|Any CPU = Release|Any CPU
9+
EndGlobalSection
10+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
11+
{E5F1A017-F109-49A1-A356-028B3627200C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
12+
{E5F1A017-F109-49A1-A356-028B3627200C}.Debug|Any CPU.Build.0 = Debug|Any CPU
13+
{E5F1A017-F109-49A1-A356-028B3627200C}.Release|Any CPU.ActiveCfg = Release|Any CPU
14+
{E5F1A017-F109-49A1-A356-028B3627200C}.Release|Any CPU.Build.0 = Release|Any CPU
15+
EndGlobalSection
16+
EndGlobal

Efmig/App.axaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Application xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:local="using:Efmig"
4+
x:Class="Efmig.App">
5+
6+
<Application.DataTemplates>
7+
<local:ViewLocator />
8+
</Application.DataTemplates>
9+
10+
<Application.Styles>
11+
<FluentTheme />
12+
</Application.Styles>
13+
</Application>

Efmig/App.axaml.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using Avalonia;
3+
using Avalonia.Controls.ApplicationLifetimes;
4+
using Avalonia.Markup.Xaml;
5+
using Efmig.Migrations;
6+
using NLog;
7+
8+
namespace Efmig;
9+
10+
public class App : Application
11+
{
12+
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
13+
14+
public override void Initialize()
15+
{
16+
AvaloniaXamlLoader.Load(this);
17+
}
18+
19+
public override void OnFrameworkInitializationCompleted()
20+
{
21+
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
22+
{
23+
try
24+
{
25+
desktop.MainWindow = Bootstrapper.CreateMainWindow();
26+
}
27+
catch (Exception e)
28+
{
29+
Logger.Error(e, "Could not create Main Window.");
30+
throw;
31+
}
32+
}
33+
34+
base.OnFrameworkInitializationCompleted();
35+
}
36+
}

Efmig/Assets/avalonia-logo.ico

172 KB
Binary file not shown.

Efmig/Efmig.csproj

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>WinExe</OutputType>
4+
<TargetFramework>net7.0</TargetFramework>
5+
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
6+
<ApplicationManifest>app.manifest</ApplicationManifest>
7+
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<AvaloniaResource Include="Assets\**" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<PackageReference Include="Avalonia" Version="11.0.0-preview5" />
20+
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview5" />
21+
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
22+
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0-preview5" />
23+
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview5" />
24+
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview5" />
25+
<PackageReference Include="CliWrap" Version="3.6.0" />
26+
<PackageReference Include="Fody" Version="6.6.4">
27+
<PrivateAssets>all</PrivateAssets>
28+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
29+
</PackageReference>
30+
<PackageReference Include="NLog" Version="5.1.2" />
31+
<PackageReference Include="ReactiveUI.Fody" Version="18.4.26" />
32+
<PackageReference Include="XamlNameReferenceGenerator" Version="1.6.1" />
33+
</ItemGroup>
34+
35+
<ItemGroup>
36+
<None Update="nlog.config">
37+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
38+
</None>
39+
</ItemGroup>
40+
41+
<ItemGroup>
42+
<Reference Include="Avalonia.Themes.Fluent">
43+
<HintPath>C:\Users\user\.nuget\packages\avalonia\0.10.18\lib\netcoreapp2.0\Avalonia.Themes.Fluent.dll</HintPath>
44+
</Reference>
45+
</ItemGroup>
46+
</Project>

Efmig/FodyWeavers.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
2+
<ReactiveUI />
3+
</Weavers>

Efmig/FodyWeavers.xsd

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3+
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
4+
<xs:element name="Weavers">
5+
<xs:complexType>
6+
<xs:all>
7+
<xs:element name="ReactiveUI" minOccurs="0" maxOccurs="1" type="xs:anyType" />
8+
</xs:all>
9+
<xs:attribute name="VerifyAssembly" type="xs:boolean">
10+
<xs:annotation>
11+
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
12+
</xs:annotation>
13+
</xs:attribute>
14+
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
15+
<xs:annotation>
16+
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
17+
</xs:annotation>
18+
</xs:attribute>
19+
<xs:attribute name="GenerateXsd" type="xs:boolean">
20+
<xs:annotation>
21+
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
22+
</xs:annotation>
23+
</xs:attribute>
24+
</xs:complexType>
25+
</xs:element>
26+
</xs:schema>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using Avalonia.Controls;
2+
using Avalonia.Controls.Documents;
3+
using Avalonia.Media;
4+
using Avalonia.Threading;
5+
6+
namespace Efmig.Migrations.Actions;
7+
8+
public class ActionContext
9+
{
10+
private readonly TextBlock _logElement;
11+
private readonly ScrollViewer _scrollViewer;
12+
13+
public ActionContext(TextBlock logElement, ScrollViewer scrollViewer, ConfigurationProfile profile)
14+
{
15+
_logElement = logElement;
16+
_scrollViewer = scrollViewer;
17+
ConfigurationProfile = profile;
18+
}
19+
20+
public ConfigurationProfile ConfigurationProfile { get; }
21+
public object Data { get; set; }
22+
23+
public void ClearLog()
24+
{
25+
Dispatcher.UIThread.InvokeAsync(() => { _logElement.Inlines!.Clear(); });
26+
}
27+
28+
private void AddLogMessage(string message, string foreground = null)
29+
{
30+
Dispatcher.UIThread.InvokeAsync(() =>
31+
{
32+
var run = new Run($"{message}\r\n");
33+
if (foreground != null)
34+
{
35+
run.Foreground = SolidColorBrush.Parse(foreground);
36+
}
37+
38+
_logElement.Inlines!.Add(run);
39+
_scrollViewer.ScrollToEnd();
40+
});
41+
}
42+
43+
public void LogInfo(string message) => AddLogMessage(message);
44+
public void LogError(string message) => AddLogMessage(message, "#FF0000");
45+
public void LogVerbose(string message) => AddLogMessage(message, "#808080");
46+
public void LogImportant(string message) => AddLogMessage(message, "#FFFF00");
47+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using CliWrap;
4+
5+
namespace Efmig.Migrations.Actions;
6+
7+
public static class CommonActionHelper
8+
{
9+
public static async Task RunDotnetEfTool(ActionContext ctx, string[] dotnetEfArgs)
10+
{
11+
ctx.ClearLog();
12+
ctx.LogInfo("Started operation: listing migrations.\r\n");
13+
14+
var targetDir = await HelperProjectInitializer.CreateHelperProject(ctx.ConfigurationProfile);
15+
16+
try
17+
{
18+
ctx.LogInfo("Running 'dotnet restore'...");
19+
20+
await Cli.Wrap("dotnet")
21+
.WithWorkingDirectory(targetDir.FullName)
22+
.WithArguments("restore")
23+
.WithStandardOutputPipe(PipeTarget.ToDelegate(ctx.LogInfo))
24+
.WithStandardErrorPipe(PipeTarget.ToDelegate(ctx.LogError))
25+
.ExecuteAsync();
26+
27+
ctx.LogInfo("Running 'dotnet tool restore'...");
28+
await Cli.Wrap("dotnet")
29+
.WithWorkingDirectory(targetDir.FullName)
30+
.WithArguments("tool restore")
31+
.WithStandardOutputPipe(PipeTarget.ToDelegate(ctx.LogInfo))
32+
.WithStandardErrorPipe(PipeTarget.ToDelegate(ctx.LogError))
33+
.ExecuteAsync();
34+
35+
ctx.LogInfo("Running 'dotnet build'...");
36+
await Cli.Wrap("dotnet")
37+
.WithWorkingDirectory(targetDir.FullName)
38+
.WithArguments("build")
39+
.WithStandardOutputPipe(PipeTarget.ToDelegate(ctx.LogInfo))
40+
.WithStandardErrorPipe(PipeTarget.ToDelegate(ctx.LogError))
41+
.ExecuteAsync();
42+
43+
44+
ctx.LogInfo("Running dotnet-ef command...");
45+
await Cli.Wrap("dotnet")
46+
.WithWorkingDirectory(targetDir.FullName)
47+
.WithArguments(args =>
48+
{
49+
args.Add("tool");
50+
args.Add("run");
51+
args.Add("dotnet-ef");
52+
53+
args.Add(dotnetEfArgs);
54+
55+
args.Add("-v");
56+
args.Add(new[] { "--context", ctx.ConfigurationProfile.DbContextFullName });
57+
args.Add(new[] { "--project", ctx.ConfigurationProfile.DbContextCsprojPath });
58+
args.Add(new[] { "--startup-project", targetDir.FullName });
59+
args.Add("--prefix-output");
60+
args.Add("--no-build");
61+
})
62+
.WithStandardOutputPipe(PipeTarget.ToDelegate(line =>
63+
{
64+
var markerLength = 9;
65+
var errorMarker = "error:".PadRight(markerLength, ' ');
66+
var verboseMarker = "verbose:".PadRight(markerLength, ' ');
67+
var infoMarker = "info:".PadRight(markerLength, ' ');
68+
69+
if (line.StartsWith(errorMarker))
70+
{
71+
ctx.LogError(line[markerLength..]);
72+
}
73+
else if (line.StartsWith(verboseMarker))
74+
{
75+
ctx.LogVerbose(line[markerLength..]);
76+
}
77+
else if (line.StartsWith(infoMarker))
78+
{
79+
ctx.LogImportant(line[markerLength..]);
80+
}
81+
else
82+
{
83+
ctx.LogInfo(line);
84+
}
85+
}))
86+
.WithStandardErrorPipe(PipeTarget.ToDelegate(ctx.LogError))
87+
.ExecuteAsync();
88+
89+
targetDir.Delete(true);
90+
}
91+
catch (Exception e)
92+
{
93+
ctx.LogError(e.ToString());
94+
}
95+
96+
ctx.LogInfo("Finished operation.");
97+
}
98+
}

0 commit comments

Comments
 (0)