Browse Source

Fix "original.dll" file permission errors during build (#13840)

* Avoid constantly recompiling Avalonia Xaml files by implementing incremental build checks
- Should be a (or even the) fix for file permission errors during builds
CompileAvaloniaXaml no longer overwrites the Compile output, but creates its own output files
- This supports incremental build checks and is safer in general
Removed unused executable features from Avalonia.Build.Tasks
- This is instead of refactoring for the new ITaskItem properties
Updated Desktop SLNF

* Fixed tests

* Touch each copied output file
pull/14700/head
Tom Edwards 2 years ago
committed by GitHub
parent
commit
0cb855adf9
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      Avalonia.Desktop.slnf
  2. 79
      packages/Avalonia/AvaloniaBuildTasks.targets
  3. 1
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  4. 116
      src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
  5. 86
      src/Avalonia.Build.Tasks/Program.cs
  6. 1
      tests/Avalonia.Build.Tasks.UnitTest/Avalonia.Build.Tasks.UnitTest.csproj
  7. 17
      tests/Avalonia.Build.Tasks.UnitTest/CompileAvaloniaXamlTaskTest.cs

5
Avalonia.Desktop.slnf

@ -51,6 +51,7 @@
"src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj", "src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj",
"tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj", "tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj",
"tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj", "tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj",
"tests\\Avalonia.Build.Tasks.UnitTest\\Avalonia.Build.Tasks.UnitTest.csproj",
"tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj", "tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj",
"tests\\Avalonia.Controls.ItemsRepeater.UnitTests\\Avalonia.Controls.ItemsRepeater.UnitTests.csproj", "tests\\Avalonia.Controls.ItemsRepeater.UnitTests\\Avalonia.Controls.ItemsRepeater.UnitTests.csproj",
"tests\\Avalonia.Controls.UnitTests\\Avalonia.Controls.UnitTests.csproj", "tests\\Avalonia.Controls.UnitTests\\Avalonia.Controls.UnitTests.csproj",
@ -58,6 +59,7 @@
"tests\\Avalonia.DesignerSupport.Tests\\Avalonia.DesignerSupport.Tests.csproj", "tests\\Avalonia.DesignerSupport.Tests\\Avalonia.DesignerSupport.Tests.csproj",
"tests\\Avalonia.Direct2D1.RenderTests\\Avalonia.Direct2D1.RenderTests.csproj", "tests\\Avalonia.Direct2D1.RenderTests\\Avalonia.Direct2D1.RenderTests.csproj",
"tests\\Avalonia.Direct2D1.UnitTests\\Avalonia.Direct2D1.UnitTests.csproj", "tests\\Avalonia.Direct2D1.UnitTests\\Avalonia.Direct2D1.UnitTests.csproj",
"tests\\Avalonia.Generators.Tests\\Avalonia.Generators.Tests.csproj",
"tests\\Avalonia.IntegrationTests.Appium\\Avalonia.IntegrationTests.Appium.csproj", "tests\\Avalonia.IntegrationTests.Appium\\Avalonia.IntegrationTests.Appium.csproj",
"tests\\Avalonia.LeakTests\\Avalonia.LeakTests.csproj", "tests\\Avalonia.LeakTests\\Avalonia.LeakTests.csproj",
"tests\\Avalonia.Markup.UnitTests\\Avalonia.Markup.UnitTests.csproj", "tests\\Avalonia.Markup.UnitTests\\Avalonia.Markup.UnitTests.csproj",
@ -65,7 +67,8 @@
"tests\\Avalonia.ReactiveUI.UnitTests\\Avalonia.ReactiveUI.UnitTests.csproj", "tests\\Avalonia.ReactiveUI.UnitTests\\Avalonia.ReactiveUI.UnitTests.csproj",
"tests\\Avalonia.Skia.RenderTests\\Avalonia.Skia.RenderTests.csproj", "tests\\Avalonia.Skia.RenderTests\\Avalonia.Skia.RenderTests.csproj",
"tests\\Avalonia.Skia.UnitTests\\Avalonia.Skia.UnitTests.csproj", "tests\\Avalonia.Skia.UnitTests\\Avalonia.Skia.UnitTests.csproj",
"tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj" "tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj",
"tests\\TestFiles\\BuildTasks\\PInvoke\\PInvoke.csproj"
] ]
} }
} }

79
packages/Avalonia/AvaloniaBuildTasks.targets

@ -58,7 +58,7 @@
<PropertyGroup> <PropertyGroup>
<BuildAvaloniaResourcesDependsOn>$(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences;_GenerateAvaloniaResourcesDependencyCache;_GenerateNoWarnForExec</BuildAvaloniaResourcesDependsOn> <BuildAvaloniaResourcesDependsOn>$(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences;_GenerateAvaloniaResourcesDependencyCache;_GenerateNoWarnForExec</BuildAvaloniaResourcesDependsOn>
<CompileAvaloniaXamlDependsOn>$(CompileAvaloniaXamlDependsOn);_GenerateNoWarnForExec</CompileAvaloniaXamlDependsOn> <CompileAvaloniaXamlDependsOn>$(CompileAvaloniaXamlDependsOn);PrepareToCompileAvaloniaXaml;_GenerateNoWarnForExec</CompileAvaloniaXamlDependsOn>
</PropertyGroup> </PropertyGroup>
<Target Name="_GenerateAvaloniaResourcesDependencyCache" BeforeTargets="GenerateAvaloniaResources"> <Target Name="_GenerateAvaloniaResourcesDependencyCache" BeforeTargets="GenerateAvaloniaResources">
@ -114,38 +114,44 @@
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:NoWarn=$(_NoWarnForExec) /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/> Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:NoWarn=$(_NoWarnForExec) /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/>
</Target> </Target>
<Target <Target Name="PrepareToCompileAvaloniaXaml">
Name="CompileAvaloniaXaml"
AfterTargets="AfterCompile"
DependsOnTargets="$(CompileAvaloniaXamlDependsOn)"
Condition="
(('@(AvaloniaResource->Count())' &gt; 0)
or ('@(AvaloniaXaml->Count())' &gt; 0))
and Exists('@(IntermediateAssembly)')
And $(DesignTimeBuild) != true
And $(EnableAvaloniaXamlCompilation) != false"
>
<PropertyGroup> <PropertyGroup>
<AvaloniaXamlReferencesTemporaryFilePath Condition="'$(AvaloniaXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/references</AvaloniaXamlReferencesTemporaryFilePath> <AvaloniaXamlReferencesTemporaryFilePath Condition="'$(AvaloniaXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/references</AvaloniaXamlReferencesTemporaryFilePath>
<AvaloniaXamlOriginalCopyFilePath Condition="'$(AvaloniaXamlOriginalCopyFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/original.dll</AvaloniaXamlOriginalCopyFilePath>
<AvaloniaXamlIlVerifyIl Condition="'$(AvaloniaXamlIlVerifyIl)' == ''">false</AvaloniaXamlIlVerifyIl> <AvaloniaXamlIlVerifyIl Condition="'$(AvaloniaXamlIlVerifyIl)' == ''">false</AvaloniaXamlIlVerifyIl>
<AvaloniaXamlIlDebuggerLaunch Condition="'$(AvaloniaXamlIlDebuggerLaunch)' == ''">false</AvaloniaXamlIlDebuggerLaunch> <AvaloniaXamlIlDebuggerLaunch Condition="'$(AvaloniaXamlIlDebuggerLaunch)' == ''">false</AvaloniaXamlIlDebuggerLaunch>
<AvaloniaXamlVerboseExceptions Condition="'$(AvaloniaXamlVerboseExceptions)' == ''">false</AvaloniaXamlVerboseExceptions> <AvaloniaXamlVerboseExceptions Condition="'$(AvaloniaXamlVerboseExceptions)' == ''">false</AvaloniaXamlVerboseExceptions>
<_AvaloniaHasCompiledXaml>true</_AvaloniaHasCompiledXaml> <_AvaloniaHasCompiledXaml>true</_AvaloniaHasCompiledXaml>
</PropertyGroup> </PropertyGroup>
<WriteLinesToFile
Condition="'$(_AvaloniaForceInternalMSBuild)' != 'true'" <ItemGroup>
File="$(AvaloniaXamlReferencesTemporaryFilePath)" <IntermediateAssembly Update="*" AvaloniaCompileOutput="%(RelativeDir)Avalonia\%(Filename)%(Extension)"/>
Lines="@(ReferencePathWithRefAssemblies)" <_DebugSymbolsIntermediatePath Update="*" AvaloniaCompileOutput="%(RelativeDir)Avalonia\%(Filename)%(Extension)"/>
Overwrite="true" /> <IntermediateRefAssembly Update="*" AvaloniaCompileOutput="%(RelativeDir)Avalonia\%(Filename)%(Extension)"/>
<ItemGroup Condition="'$(_AvaloniaForceInternalMSBuild)' != 'true'"> <CompileAvaloniaXamlInputs Include="@(IntermediateAssembly);@(_DebugSymbolsIntermediatePath);@(IntermediateRefAssembly)"/>
<CompileAvaloniaXamlOutputs Include="@(CompileAvaloniaXamlInputs->'%(AvaloniaCompileOutput)')"/>
<CompileAvaloniaXamlInputs Include="@(AvaloniaResource);@(AvaloniaXaml)"/>
<FileWrites Include="@(CompileAvaloniaXamlOutputs)"/>
<FileWrites Include="$(AvaloniaXamlReferencesTemporaryFilePath)" /> <FileWrites Include="$(AvaloniaXamlReferencesTemporaryFilePath)" />
</ItemGroup> </ItemGroup>
</Target>
<Target
Name="CompileAvaloniaXaml"
AfterTargets="AfterCompile"
DependsOnTargets="$(CompileAvaloniaXamlDependsOn)"
Inputs="@(CompileAvaloniaXamlInputs)"
Outputs="@(CompileAvaloniaXamlOutputs)"
Condition="'@(AvaloniaResource)@(AvaloniaXaml)' != '' AND $(DesignTimeBuild) != true AND $(EnableAvaloniaXamlCompilation) != false">
<ReadLinesFromFile File="$(AvaloniaXamlReferencesTemporaryFilePath)" Condition="'$(_AvaloniaUseExternalMSBuild)' != 'true' AND '@(ReferencePathWithRefAssemblies)' == ''">
<Output TaskParameter="Lines" ItemName="ReferencePathWithRefAssemblies"/>
</ReadLinesFromFile>
<CompileAvaloniaXamlTask <CompileAvaloniaXamlTask
Condition="'$(_AvaloniaUseExternalMSBuild)' != 'true'" Condition="'$(_AvaloniaUseExternalMSBuild)' != 'true'"
AssemblyFile="@(IntermediateAssembly)" AssemblyFile="@(IntermediateAssembly)"
ReferencesFilePath="$(AvaloniaXamlReferencesTemporaryFilePath)" References="@(ReferencePathWithRefAssemblies)"
OriginalCopyPath="$(AvaloniaXamlOriginalCopyFilePath)"
RefAssemblyFile="@(IntermediateRefAssembly)" RefAssemblyFile="@(IntermediateRefAssembly)"
ProjectDirectory="$(MSBuildProjectDirectory)" ProjectDirectory="$(MSBuildProjectDirectory)"
VerifyIl="$(AvaloniaXamlIlVerifyIl)" VerifyIl="$(AvaloniaXamlIlVerifyIl)"
@ -157,14 +163,39 @@
DebuggerLaunch="$(AvaloniaXamlIlDebuggerLaunch)" DebuggerLaunch="$(AvaloniaXamlIlDebuggerLaunch)"
DefaultCompileBindings="$(AvaloniaUseCompiledBindingsByDefault)" DefaultCompileBindings="$(AvaloniaUseCompiledBindingsByDefault)"
VerboseExceptions="$(AvaloniaXamlVerboseExceptions)" VerboseExceptions="$(AvaloniaXamlVerboseExceptions)"
AnalyzerConfigFiles="@(EditorConfigFiles)"> AnalyzerConfigFiles="@(EditorConfigFiles)"/>
<Output TaskParameter="WrittenFilePaths" ItemName="FileWrites" />
</CompileAvaloniaXamlTask> <WriteLinesToFile File="$(AvaloniaXamlReferencesTemporaryFilePath)" Lines="@(ReferencePathWithRefAssemblies)" Overwrite="true"
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'" />
<Exec <Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'" Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:NoWarn=$(_NoWarnForExec) /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/> Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:NoWarn=$(_NoWarnForExec) /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/>
</Target> </Target>
<Target Name="InjectAvaloniaXamlOutput" DependsOnTargets="PrepareToCompileAvaloniaXaml" AfterTargets="CompileAvaloniaXaml" BeforeTargets="CopyFilesToOutputDirectory;BuiltProjectOutputGroup"
Condition="'@(AvaloniaResource)@(AvaloniaXaml)' != '' AND $(EnableAvaloniaXamlCompilation) != false">
<ItemGroup>
<_AvaloniaXamlCompiledAssembly Include="@(IntermediateAssembly->Metadata('AvaloniaCompileOutput'))"/>
<IntermediateAssembly Remove="@(IntermediateAssembly)"/>
<IntermediateAssembly Include="@(_AvaloniaXamlCompiledAssembly)"/>
<_AvaloniaXamlCompiledRefAssembly Include="@(IntermediateRefAssembly->Metadata('AvaloniaCompileOutput'))"/>
<IntermediateRefAssembly Remove="@(IntermediateRefAssembly)"/>
<IntermediateRefAssembly Include="@(_AvaloniaXamlCompiledRefAssembly)"/>
<_AvaloniaXamlCompiledSymbols Include="@(_DebugSymbolsIntermediatePath->Metadata('AvaloniaCompileOutput'))"/>
<_DebugSymbolsIntermediatePath Remove="@(_DebugSymbolsIntermediatePath)"/>
<_DebugSymbolsIntermediatePath Include="@(_AvaloniaXamlCompiledSymbols)"/>
</ItemGroup>
</Target>
<Target Name="Avalonia_CollectUpToDateCheckOutputDesignTime" Condition="'@(AvaloniaResource)@(AvaloniaXaml)' != '' AND $(EnableAvaloniaXamlCompilation) != false"
BeforeTargets="CollectUpToDateCheckOutputDesignTime" DependsOnTargets="PrepareToCompileAvaloniaXaml">
<ItemGroup>
<UpToDateCheckOutput Include="@(CompileAvaloniaXamlOutputs)"/>
</ItemGroup>
</Target>
<ItemGroup> <ItemGroup>
<UpToDateCheckInput Include="@(AvaloniaResource)" /> <UpToDateCheckInput Include="@(AvaloniaResource)" />

1
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard2.0</TargetFrameworks>
<OutputType>exe</OutputType>
<GenerateDocumentationFile>false</GenerateDocumentationFile> <GenerateDocumentationFile>false</GenerateDocumentationFile>
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder> <BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
<DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants> <DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants>

116
src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.Build.Framework; using Microsoft.Build.Framework;
@ -8,110 +7,70 @@ namespace Avalonia.Build.Tasks
{ {
public class CompileAvaloniaXamlTask: ITask public class CompileAvaloniaXamlTask: ITask
{ {
public const string AvaloniaCompileOutputMetadataName = "AvaloniaCompileOutput";
public bool Execute() public bool Execute()
{ {
Enum.TryParse(ReportImportance, true, out MessageImportance outputImportance); Enum.TryParse(ReportImportance, true, out MessageImportance outputImportance);
var writtenFilePaths = new List<string>();
OutputPath ??= AssemblyFile;
RefOutputPath ??= RefAssemblyFile;
var outputPdb = GetPdbPath(OutputPath);
var input = AssemblyFile;
var refInput = RefOutputPath;
var inputPdb = GetPdbPath(input);
// Make a copy and delete the original file to prevent MSBuild from thinking that everything is OK
if (OriginalCopyPath != null)
{
var originalCopyPathRef = Path.ChangeExtension(OriginalCopyPath, ".ref.dll");
File.Copy(AssemblyFile, OriginalCopyPath, true); var outputPath = AssemblyFile.GetMetadata(AvaloniaCompileOutputMetadataName);
writtenFilePaths.Add(OriginalCopyPath); var refOutputPath = RefAssemblyFile?.GetMetadata(AvaloniaCompileOutputMetadataName);
input = OriginalCopyPath;
File.Delete(AssemblyFile);
if (File.Exists(inputPdb)) Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
{ if (!string.IsNullOrEmpty(refOutputPath))
var copyPdb = GetPdbPath(OriginalCopyPath); {
File.Copy(inputPdb, copyPdb, true); Directory.CreateDirectory(Path.GetDirectoryName(refOutputPath));
writtenFilePaths.Add(copyPdb);
File.Delete(inputPdb);
inputPdb = copyPdb;
}
if (!string.IsNullOrWhiteSpace(RefAssemblyFile) && File.Exists(RefAssemblyFile))
{
// We also copy ref assembly just for case if needed later for testing.
// But do not remove the original one, as MSBuild actually complains about it with multi-thread compiling.
File.Copy(RefAssemblyFile, originalCopyPathRef, true);
writtenFilePaths.Add(originalCopyPathRef);
refInput = originalCopyPathRef;
}
} }
var msg = $"CompileAvaloniaXamlTask -> AssemblyFile:{AssemblyFile}, ProjectDirectory:{ProjectDirectory}, OutputPath:{OutputPath}"; var msg = $"CompileAvaloniaXamlTask -> AssemblyFile:{AssemblyFile}, ProjectDirectory:{ProjectDirectory}, OutputPath:{outputPath}";
BuildEngine.LogMessage(msg, outputImportance < MessageImportance.Low ? MessageImportance.High : outputImportance); BuildEngine.LogMessage(msg, outputImportance < MessageImportance.Low ? MessageImportance.High : outputImportance);
var res = XamlCompilerTaskExecutor.Compile(BuildEngine, var res = XamlCompilerTaskExecutor.Compile(BuildEngine,
input, OutputPath, AssemblyFile.ItemSpec, outputPath,
refInput, RefOutputPath, RefAssemblyFile?.ItemSpec, refOutputPath,
File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(), References?.Select(i => i.ItemSpec).ToArray() ?? Array.Empty<string>(),
ProjectDirectory, VerifyIl, DefaultCompileBindings, outputImportance, ProjectDirectory, VerifyIl, DefaultCompileBindings, outputImportance,
new XamlCompilerDiagnosticsFilter(AnalyzerConfigFiles), new XamlCompilerDiagnosticsFilter(AnalyzerConfigFiles),
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null, (SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null,
SkipXamlCompilation, DebuggerLaunch, VerboseExceptions); SkipXamlCompilation, DebuggerLaunch, VerboseExceptions);
if (!res.Success)
{
WrittenFilePaths = writtenFilePaths.ToArray();
return false;
}
if (!res.WrittenFile) if (res.Success && !res.WrittenFile)
{ {
File.Copy(input, OutputPath, true); // To simplify incremental build checks, copy the input files to the expected output locations even if the Xaml compiler didn't do anything.
if (File.Exists(inputPdb)) CopyAndTouch(AssemblyFile.ItemSpec, outputPath);
File.Copy(inputPdb, outputPdb, true); CopyAndTouch(Path.ChangeExtension(AssemblyFile.ItemSpec, ".pdb"), Path.ChangeExtension(outputPath, ".pdb"));
}
else if (!string.IsNullOrWhiteSpace(RefOutputPath) && File.Exists(RefOutputPath))
writtenFilePaths.Add(RefOutputPath);
writtenFilePaths.Add(OutputPath); if (!string.IsNullOrEmpty(refOutputPath))
if (File.Exists(outputPdb)) {
writtenFilePaths.Add(outputPdb); CopyAndTouch(RefAssemblyFile.ItemSpec, refOutputPath);
}
}
WrittenFilePaths = writtenFilePaths.ToArray(); return res.Success;
return true;
} }
string GetPdbPath(string p) private static void CopyAndTouch(string source, string destination)
{ {
var d = Path.GetDirectoryName(p); File.Copy(source, destination, overwrite: true);
var f = Path.GetFileNameWithoutExtension(p); File.SetLastWriteTimeUtc(destination, DateTime.UtcNow);
var rv = f + ".pdb";
if (d != null)
rv = Path.Combine(d, rv);
return rv;
} }
[Required]
public string AssemblyFile { get; set; }
[Required]
public string ReferencesFilePath { get; set; }
[Required]
public string OriginalCopyPath { get; set; }
[Required] [Required]
public string ProjectDirectory { get; set; } public string ProjectDirectory { get; set; }
public string RefAssemblyFile { get; set; } [Required]
public string RefOutputPath { get; set; } public ITaskItem AssemblyFile { get; set; }
public string OutputPath { get; set; } public ITaskItem? RefAssemblyFile { get; set; }
public ITaskItem[]? References { get; set; }
public bool VerifyIl { get; set; } public bool VerifyIl { get; set; }
public bool DefaultCompileBindings { get; set; } public bool DefaultCompileBindings { get; set; }
public bool SkipXamlCompilation { get; set; } public bool SkipXamlCompilation { get; set; }
public string AssemblyOriginatorKeyFile { get; set; } public string AssemblyOriginatorKeyFile { get; set; }
public bool SignAssembly { get; set; } public bool SignAssembly { get; set; }
public bool DelaySign { get; set; } public bool DelaySign { get; set; }
@ -124,10 +83,7 @@ namespace Avalonia.Build.Tasks
public bool DebuggerLaunch { get; set; } public bool DebuggerLaunch { get; set; }
public bool VerboseExceptions { get; set; } public bool VerboseExceptions { get; set; }
public ITaskItem[] AnalyzerConfigFiles { get; set; } public ITaskItem[] AnalyzerConfigFiles { get; set; }
[Output]
public string[] WrittenFilePaths { get; private set; } = Array.Empty<string>();
} }
} }

86
src/Avalonia.Build.Tasks/Program.cs

@ -1,86 +0,0 @@
using System;
using System.Collections;
using System.IO;
using System.Linq;
using Microsoft.Build.Framework;
namespace Avalonia.Build.Tasks
{
public class Program
{
private const string OriginalDll = "original.dll";
private const string References = "references";
private const string OutDll = "out.dll";
static int Main(string[] args)
{
if (args.Length < 3)
{
if (args.Length == 1)
{
args = new[] {OriginalDll, References, OutDll}
.Select(x => Path.Combine(args[0], x)).ToArray();
}
else
{
const string referencesOutputPath = "path/to/Avalonia/samples/Sandbox/obj/Debug/net60/Avalonia";
Console.WriteLine(@$"Usage:
1) dotnet ./Avalonia.Build.Tasks.dll <ReferencesOutputPath>
, where <ReferencesOutputPath> likes {referencesOutputPath}
2) dotnet ./Avalonia.Build.Tasks.dll <AssemblyFilePath> <ReferencesFilePath> <OutputPath> <RefAssemblyFile>
, where:
- <AssemblyFilePath> likes {referencesOutputPath}/{OriginalDll}
- <ReferencesFilePath> likes {referencesOutputPath}/{References}
- <OutputPath> likes {referencesOutputPath}/{OutDll}
- <RefAssemblyFile> Likes {referencesOutputPath}/original.ref.dll");
return 1;
}
}
return new CompileAvaloniaXamlTask()
{
AssemblyFile = args[0],
ReferencesFilePath = args[1],
OutputPath = args[2],
RefAssemblyFile = args.Length > 3 ? args[3] : null,
BuildEngine = new ConsoleBuildEngine(),
ProjectDirectory = Directory.GetCurrentDirectory(),
VerifyIl = true
}.Execute() ?
0 :
2;
}
class ConsoleBuildEngine : IBuildEngine
{
public void LogErrorEvent(BuildErrorEventArgs e)
{
Console.WriteLine($"ERROR: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
}
public void LogWarningEvent(BuildWarningEventArgs e)
{
Console.WriteLine($"WARNING: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
}
public void LogMessageEvent(BuildMessageEventArgs e)
{
Console.WriteLine($"MESSAGE: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
}
public void LogCustomEvent(CustomBuildEventArgs e)
{
Console.WriteLine($"CUSTOM: {e.Message}");
}
public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties,
IDictionary targetOutputs) => throw new NotSupportedException();
public bool ContinueOnError { get; }
public int LineNumberOfTaskNode { get; }
public int ColumnNumberOfTaskNode { get; }
public string ProjectFileOfTaskNode { get; }
}
}
}

1
tests/Avalonia.Build.Tasks.UnitTest/Avalonia.Build.Tasks.UnitTest.csproj

@ -25,6 +25,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" /> <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.1.548" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

17
tests/Avalonia.Build.Tasks.UnitTest/CompileAvaloniaXamlTaskTest.cs

@ -1,6 +1,8 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using Microsoft.Build.Utilities;
using Xunit; using Xunit;
namespace Avalonia.Build.Tasks.UnitTest; namespace Avalonia.Build.Tasks.UnitTest;
@ -13,19 +15,16 @@ public class CompileAvaloniaXamlTaskTest
{ {
using var engine = UnitTestBuildEngine.Start(); using var engine = UnitTestBuildEngine.Start();
var basePath = Path.Combine(Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath), "Assets"); var basePath = Path.Combine(Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath), "Assets");
var originalAssemblyPath = Path.Combine(basePath, var assembly = new TaskItem(Path.Combine(basePath, "PInvoke.dll"));
"PInvoke.dll"); assembly.SetMetadata(CompileAvaloniaXamlTask.AvaloniaCompileOutputMetadataName, Path.Combine(basePath, "Avalonia", Path.GetFileName(assembly.ItemSpec)));
var referencesPath = Path.Combine(basePath, var references = File.ReadAllLines(Path.Combine(basePath, "PInvoke.dll.refs")).Select(p => new TaskItem(p)).ToArray();
"PInvoke.dll.refs");
var compiledAssemblyPath = "PInvoke.dll";
Assert.True(File.Exists(originalAssemblyPath), $"The original {originalAssemblyPath} don't exists."); Assert.True(File.Exists(assembly.ItemSpec), $"The original {assembly.ItemSpec} don't exist.");
new CompileAvaloniaXamlTask() new CompileAvaloniaXamlTask()
{ {
AssemblyFile = originalAssemblyPath, AssemblyFile = assembly,
ReferencesFilePath = referencesPath, References = references,
OutputPath = compiledAssemblyPath,
RefAssemblyFile = null, RefAssemblyFile = null,
BuildEngine = engine, BuildEngine = engine,
ProjectDirectory = Directory.GetCurrentDirectory(), ProjectDirectory = Directory.GetCurrentDirectory(),

Loading…
Cancel
Save