Emulate xbuild targeting behavior on Mono. Closes #1.

- Added subprocess startup with assembly binding redirection to enforce MSBuild version 12 system (https://github.com/mono/mono/blob/master/mcs/tools/xbuild/data/xbuild.exe.config.in). I don't know how many nasty side effects this causes as the code is pretty poor, so pleeeeeaaaaaase do report bugs on this.
release-1.1.0
Icedream 2015-01-16 10:35:58 +01:00
parent 364fee11dd
commit 853140b905
7 changed files with 186 additions and 46 deletions

View File

@ -1,6 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <runtime>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> <generatePublisherEvidence enabled="false" />
</startup> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-100.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Engine" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-100.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> </configuration>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<generatePublisherEvidence enabled="false" />
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-100.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Engine" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-100.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -62,6 +62,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CommandLineOptions.cs" /> <Compile Include="CommandLineOptions.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RepositoryExtensions.cs" /> <Compile Include="RepositoryExtensions.cs" />
@ -88,6 +89,7 @@
<EmbeddedResource Include="costura64\git2-91fa31f.dll" /> <EmbeddedResource Include="costura64\git2-91fa31f.dll" />
<EmbeddedResource Include="costura32\*.so" /> <EmbeddedResource Include="costura32\*.so" />
<EmbeddedResource Include="costura64\*.so" /> <EmbeddedResource Include="costura64\*.so" />
<EmbeddedResource Include="AppDomainConfigurations\BuildNET45.xml" />
<Content Include="FodyWeavers.xml"> <Content Include="FodyWeavers.xml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Content> </Content>

14
src/updater/Extensions.cs Normal file
View File

@ -0,0 +1,14 @@
using System;
namespace CitizenMP.Server.Installer
{
internal static class Extensions
{
public static bool IsWin32(this OperatingSystem os)
{
return os.Platform == PlatformID.Win32NT ||
os.Platform == PlatformID.Win32S ||
os.Platform == PlatformID.Win32Windows;
}
}
}

View File

@ -13,7 +13,6 @@ using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution; using Microsoft.Build.Execution;
using Microsoft.Build.Framework; using Microsoft.Build.Framework;
using Mono.Unix.Native; using Mono.Unix.Native;
using Project = Microsoft.Build.BuildEngine.Project;
using UnixSyscall = Mono.Unix.Native.Syscall; using UnixSyscall = Mono.Unix.Native.Syscall;
namespace CitizenMP.Server.Installer namespace CitizenMP.Server.Installer
@ -59,6 +58,13 @@ namespace CitizenMP.Server.Installer
private static int Main(string[] args) private static int Main(string[] args)
{ {
var monoRun = RunWithMonoConfiguration(args);
if (monoRun.Item1)
{
// The main stuff already ran in a subprocess
return monoRun.Item2;
}
// Parse cmdline arguments // Parse cmdline arguments
var options = new CommandLineOptions(); var options = new CommandLineOptions();
//args = args.DefaultIfEmpty("--help").ToArray(); //args = args.DefaultIfEmpty("--help").ToArray();
@ -238,7 +244,7 @@ namespace CitizenMP.Server.Installer
{ {
{"Configuration", "Release"}, {"Configuration", "Release"},
{"Platform", "Any CPU"}, {"Platform", "Any CPU"},
{"DebugType", IsWin32() ? "None" : "pdbonly"}, {"DebugType", Environment.OSVersion.IsWin32() ? "None" : "pdbonly"},
{"DebugSymbols", false.ToString()}, {"DebugSymbols", false.ToString()},
{"OutputPath", binOutputDirectory.FullName}, {"OutputPath", binOutputDirectory.FullName},
{"AllowedReferenceRelatedFileExtensions", "\".mdb\"=\"\";\".pdb\"=\"\";\".xml\"=\"\""} {"AllowedReferenceRelatedFileExtensions", "\".mdb\"=\"\";\".pdb\"=\"\";\".xml\"=\"\""}
@ -315,6 +321,62 @@ namespace CitizenMP.Server.Installer
return 0; return 0;
} }
private static Tuple<bool, int> RunWithMonoConfiguration(string[] args)
{
if (Environment.OSVersion.IsWin32())
{
// .NET Framework does everything properly anyways
return new Tuple<bool, int>(false, 0);
}
var engineAssembly =
Assembly.Load(
"Microsoft.Build.Engine, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.GetName();
if (engineAssembly.Version.Major < 12)
{
//var baseDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var baseDir = Path.GetDirectoryName(Assembly.Load("CommandLine").Location);
if (baseDir == null)
throw new DirectoryNotFoundException("Could not find base directory");
var tempExePath = Path.Combine(baseDir, new Random().Next(10000, 99999) + ".exe");
File.Copy(Assembly.GetExecutingAssembly().Location, tempExePath);
var tempConfigPath = tempExePath + ".config";
using (var tempConfig = File.OpenWrite(tempConfigPath))
{
using (
var srcConfig =
Assembly.GetExecutingAssembly()
.GetManifestResourceStream(
"CitizenMP.Server.Installer.AppDomainConfigurations.BuildNET45.xml"))
{
if (srcConfig == null)
throw new FileNotFoundException("Could not find config resource");
srcConfig.CopyTo(tempConfig);
srcConfig.Flush();
}
}
AppDomain.CurrentDomain.DomainUnload += (sender, e) =>
{
File.Delete(tempConfigPath);
File.Delete(tempExePath);
};
var arguments = string.Join(" ",
new[] {tempExePath}.Concat(args)
.Select(a => "\"" + a.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""));
var exitCode = RunProcess("mono", arguments, new Dictionary<string, string>
{
{"MONO_IOMAP", "all"}
});
return new Tuple<bool, int>(true, exitCode);
}
return new Tuple<bool, int>(false, 0);
}
private static bool Build(string projectFilePath, IDictionary<string, string> buildProperties, private static bool Build(string projectFilePath, IDictionary<string, string> buildProperties,
LoggerVerbosity verbosity, string logPath = null) LoggerVerbosity verbosity, string logPath = null)
{ {
@ -349,7 +411,7 @@ namespace CitizenMP.Server.Installer
loggers.Add(new ConsoleLogger(verbosity) {ShowSummary = false}); loggers.Add(new ConsoleLogger(verbosity) {ShowSummary = false});
// Import/Update Mozilla certs for NuGet to not fail out on non-Windows machines // Import/Update Mozilla certs for NuGet to not fail out on non-Windows machines
if (!IsWin32()) if (!Environment.OSVersion.IsWin32())
{ {
try try
{ {
@ -357,15 +419,18 @@ namespace CitizenMP.Server.Installer
{ {
if (s == null || !s.Contains("X.509 Certificate")) if (s == null || !s.Contains("X.509 Certificate"))
return; return;
writer.WriteLine("y"); writer.WriteLine("yes");
}); });
// TODO: Make sure this does not fail out by checking if mozroots is installed // TODO: Make sure this does not fail out by checking if mozroots is installed
Console.WriteLine("Updating SSL certificates for NuGet..."); Console.WriteLine("Updating SSL certificates for NuGet...");
Run("mozroots", "--import --sync --quiet"); RunProcessThrowOnException("mozroots", "--import --sync --quiet");
Run("certmgr", "-ssl https://go.microsoft.com", automaticYesResponder); RunProcessThrowOnException("certmgr", "-ssl https://go.microsoft.com",
Run("certmgr", "-ssl https://nugetgallery.blob.core.windows.net", automaticYesResponder); lineProcessor: automaticYesResponder);
Run("certmgr", "-ssl https://nuget.org", automaticYesResponder); RunProcessThrowOnException("certmgr", "-ssl https://nugetgallery.blob.core.windows.net",
lineProcessor: automaticYesResponder);
RunProcessThrowOnException("certmgr", "-ssl https://nuget.org",
lineProcessor: automaticYesResponder);
} }
catch (Exception error) catch (Exception error)
{ {
@ -386,18 +451,27 @@ namespace CitizenMP.Server.Installer
} }
// Use a different build route if running on the Mono interpreter // Use a different build route if running on the Mono interpreter
if (!IsWin32()) if (!Environment.OSVersion.IsWin32())
{ {
// Build doesn't work with the new API on Mono, use the deprecated api
Console.WriteLine("Building server binaries..."); Console.WriteLine("Building server binaries...");
#pragma warning disable 618 #pragma warning disable 618
// Build doesn't work with the new API on Mono, use the deprecated api
var engine = Engine.GlobalEngine;
// loggers
foreach (var logger in loggers) foreach (var logger in loggers)
Engine.GlobalEngine.RegisterLogger(logger); engine.RegisterLogger(logger);
var project = new Project(Engine.GlobalEngine) {BuildEnabled = true};
project.Load(projectFilePath); // Apply build properties
var buildPropertiesConverted = new BuildPropertyGroup();
engine.GlobalProperties = buildPropertiesConverted;
foreach (var property in buildProperties) foreach (var property in buildProperties)
project.GlobalProperties.SetProperty(property.Key, property.Value); buildPropertiesConverted.SetProperty(property.Key, property.Value);
var result = project.Build();
// Load project
var result = engine.BuildProjectFile(projectFilePath, new string[0], null, null,
BuildSettings.None,
null);
#pragma warning restore 618 #pragma warning restore 618
return result; return result;
} }
@ -406,7 +480,8 @@ namespace CitizenMP.Server.Installer
{ {
Console.WriteLine("Building server binaries..."); Console.WriteLine("Building server binaries...");
var buildReq = new BuildRequestData(projectFilePath, buildProperties, null, new[] {"Build"}, null); var buildReq = new BuildRequestData(projectFilePath, buildProperties, null, new[] {"Build"},
null);
var result = BuildManager.DefaultBuildManager.Build( var result = BuildManager.DefaultBuildManager.Build(
new BuildParameters(pc) new BuildParameters(pc)
@ -424,18 +499,42 @@ namespace CitizenMP.Server.Installer
} }
} }
private static void Run(string name, string args, Action<string, StreamWriter> lineProcessor = null) private static void RunProcessThrowOnException(string name, string args,
IDictionary<string, string> envVars = null,
Action<string, StreamWriter> lineProcessor = null)
{ {
using (var p = Process.Start(new ProcessStartInfo var exitCode = RunProcess(name, args, envVars, lineProcessor);
if (exitCode != 0)
{
throw new Exception(string.Format("Process \"{0} {1}\" exited with error code {2}",
name, args, exitCode));
}
}
private static int RunProcess(string name, string args, IDictionary<string, string> envVars = null,
Action<string, StreamWriter> lineProcessor = null)
{
using (var p = new Process
{
StartInfo =
{ {
Arguments = args, Arguments = args,
FileName = name, FileName = name,
UseShellExecute = false, UseShellExecute = false,
CreateNoWindow = true, CreateNoWindow = true,
WorkingDirectory = Environment.CurrentDirectory,
RedirectStandardInput = lineProcessor != null, RedirectStandardInput = lineProcessor != null,
RedirectStandardOutput = lineProcessor != null RedirectStandardOutput = lineProcessor != null
})) }
})
{ {
if (envVars != null)
foreach (KeyValuePair<string, string> i in envVars)
p.StartInfo.EnvironmentVariables.Add(i.Key, i.Value);
p.Start();
if (lineProcessor == null) if (lineProcessor == null)
{ {
p.WaitForExit(); p.WaitForExit();
@ -449,19 +548,8 @@ namespace CitizenMP.Server.Installer
} }
} }
if (p.ExitCode != 0) return p.ExitCode;
{
throw new Exception(string.Format("Process \"{0} {1}\" exited with error code {2}",
name, args, p.ExitCode));
} }
} }
} }
private static bool IsWin32()
{
return Environment.OSVersion.Platform == PlatformID.Win32NT ||
Environment.OSVersion.Platform == PlatformID.Win32S ||
Environment.OSVersion.Platform == PlatformID.Win32Windows;
}
}
} }

View File

@ -1,6 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <runtime>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> <generatePublisherEvidence enabled="false" />
</startup> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-100.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Engine" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-100.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> </configuration>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Weavers> <Weavers>
<Costura/> <Costura CreateTemporaryAssemblies="true"/>
</Weavers> </Weavers>