Browse Source

Support parallel building of projects in tye.yaml (#405)

- Generate an msbuild project on the fly to build all projects described in tye.yaml

Fixes #389
pull/408/head
David Fowler 6 years ago
committed by GitHub
parent
commit
11ada3f1f7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 90
      src/Microsoft.Tye.Hosting/ProcessRunner.cs

90
src/Microsoft.Tye.Hosting/ProcessRunner.cs

@ -8,6 +8,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@ -45,20 +46,23 @@ namespace Microsoft.Tye.Hosting
private async Task BuildAndRunProjects(Application application)
{
var projectGroups = new Dictionary<string, ProjectGroup>();
var groupCount = 0;
foreach (var service in application.Services.Values)
{
var serviceDescription = service.Description;
string path;
string args;
var buildArgs = string.Empty;
var buildProperties = string.Empty;
string workingDirectory;
if (serviceDescription.RunInfo is ProjectRunInfo project)
{
path = project.RunCommand;
workingDirectory = project.ProjectFile.Directory.FullName;
args = project.Args == null ? project.RunArguments : project.RunArguments + " " + project.Args;
buildArgs = project.BuildProperties.Aggregate(string.Empty, (current, property) => current + $" /p:{property.Key}={property.Value}").TrimStart();
buildProperties = project.BuildProperties.Aggregate(string.Empty, (current, property) => current + $";{property.Key}={property.Value}").TrimStart(';');
service.Status.ProjectFilePath = project.ProjectFile.FullName;
}
@ -90,34 +94,68 @@ namespace Microsoft.Tye.Hosting
project2.Build &&
_options.BuildProjects)
{
// Sometimes building can fail because of file locking (like files being open in VS)
_logger.LogInformation("Building project {ProjectFile}", service.Status.ProjectFilePath);
if (!projectGroups.TryGetValue(buildProperties, out var projectGroup))
{
projectGroup = new ProjectGroup("ProjectGroup" + groupCount);
projectGroups[buildProperties] = projectGroup;
groupCount++;
}
service.Logs.OnNext($"dotnet build \"{service.Status.ProjectFilePath}\" {buildArgs} /nologo");
projectGroup.Services.Add(service);
}
}
if (projectGroups.Count > 0)
{
using var directory = TempDirectory.Create();
var buildResult = await ProcessUtil.RunAsync("dotnet", $"build \"{service.Status.ProjectFilePath}\" {buildArgs} /nologo", throwOnError: false, workingDirectory: workingDirectory);
var projectPath = Path.Combine(directory.DirectoryPath, Path.GetRandomFileName() + ".proj");
service.Logs.OnNext(buildResult.StandardOutput);
var sb = new StringBuilder();
sb.AppendLine(@"<Project DefaultTargets=""Build"">
<ItemGroup>");
if (buildResult.ExitCode != 0)
foreach (var group in projectGroups)
{
foreach (var p in group.Value.Services)
{
_logger.LogInformation("Building {ProjectFile} failed with exit code {ExitCode}: \r\n" + buildResult.StandardOutput, service.Status.ProjectFilePath, buildResult.ExitCode);
return;
sb.AppendLine($" <{group.Value.GroupName} Include=\"{p.Status.ProjectFilePath}\" />");
}
sb.AppendLine(@" </ItemGroup>");
}
}
foreach (var s in application.Services)
{
switch (s.Value.ServiceType)
sb.AppendLine($@" <Target Name=""Build"">");
foreach (var group in projectGroups)
{
case ServiceType.Executable:
LaunchService(application, s.Value);
break;
case ServiceType.Project:
LaunchService(application, s.Value);
break;
};
sb.AppendLine($@" <MsBuild Projects=""@({group.Value.GroupName})"" Properties=""{group.Key}"" BuildInParallel=""true"" />");
}
sb.AppendLine(" </Target>");
sb.AppendLine("</Project>");
File.WriteAllText(projectPath, sb.ToString());
_logger.LogInformation("Building projects");
var buildResult = await ProcessUtil.RunAsync("dotnet", $"build \"{projectPath}\" /nologo", throwOnError: false, workingDirectory: application.ContextDirectory);
if (buildResult.ExitCode != 0)
{
_logger.LogInformation("Building projects failed with exit code {ExitCode}: \r\n" + buildResult.StandardOutput, buildResult.ExitCode);
return;
}
foreach (var s in application.Services)
{
switch (s.Value.ServiceType)
{
case ServiceType.Executable:
LaunchService(application, s.Value);
break;
case ServiceType.Project:
LaunchService(application, s.Value);
break;
};
}
}
}
@ -398,5 +436,15 @@ namespace Microsoft.Tye.Hosting
public CancellationTokenSource StoppedTokenSource { get; } = new CancellationTokenSource();
}
private class ProjectGroup
{
public ProjectGroup(string groupName)
{
GroupName = groupName;
}
public List<Service> Services { get; } = new List<Service>();
public string GroupName { get; }
}
}
}

Loading…
Cancel
Save