Browse Source

Fixed bug in build engine: the mapping solution configuration->project configuration was not applied when building only modified projects.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@4008 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
cdc98c365b
  1. 24
      src/Main/Base/Project/Src/Project/BuildEngine.cs
  2. 52
      src/Main/Base/Project/Src/Project/IProject.cs
  3. 14
      src/Main/Base/Project/Src/Services/ProjectService/CompileModifiedProjectsOnly.cs
  4. 5
      src/Main/ICSharpCode.SharpDevelop.BuildWorker/Interprocess/HostProcess.cs
  5. 50
      src/Main/ICSharpCode.SharpDevelop.BuildWorker/Interprocess/WorkerProcess.cs
  6. 4
      src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs

24
src/Main/Base/Project/Src/Project/BuildEngine.cs

@ -172,7 +172,6 @@ namespace ICSharpCode.SharpDevelop.Project @@ -172,7 +172,6 @@ namespace ICSharpCode.SharpDevelop.Project
engine.buildStart = DateTime.Now;
engine.combinedBuildFeedbackSink = realtimeBuildFeedbackSink;
engine.progressMonitor = progressMonitor;
engine.configMatchings = solution.GetActiveConfigurationsAndPlatformsForProjects(options.SolutionConfiguration, options.SolutionPlatform);
try {
engine.rootNode = engine.CreateBuildGraph(project);
} catch (CyclicDependencyException ex) {
@ -206,6 +205,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -206,6 +205,7 @@ namespace ICSharpCode.SharpDevelop.Project
{
readonly BuildEngine engine;
internal readonly IBuildable project;
/// <summary>The build options used for this node. Might be null.</summary>
internal ProjectBuildOptions options;
internal BuildNode[] dependencies;
/// <summary>specifies whether the node has been constructed completely (all dependencies initialized)</summary>
@ -287,7 +287,6 @@ namespace ICSharpCode.SharpDevelop.Project @@ -287,7 +287,6 @@ namespace ICSharpCode.SharpDevelop.Project
readonly Dictionary<IBuildable, BuildNode> nodeDict = new Dictionary<IBuildable, BuildNode>();
readonly BuildOptions options;
IProgressMonitor progressMonitor;
List<Solution.ProjectConfigurationPlatformMatching> configMatchings;
BuildNode rootNode;
IBuildable rootProject;
BuildResults results = new BuildResults();
@ -324,26 +323,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -324,26 +323,7 @@ namespace ICSharpCode.SharpDevelop.Project
{
IBuildable project = node.project;
// Create options for building the project
node.options = new ProjectBuildOptions(project == rootProject ? options.ProjectTarget : options.TargetForDependencies);
// find the project configuration
foreach (var matching in configMatchings) {
if (matching.Project == project) {
node.options.Configuration = matching.Configuration;
node.options.Platform = matching.Platform;
}
}
if (string.IsNullOrEmpty(node.options.Configuration))
node.options.Configuration = options.SolutionConfiguration;
if (string.IsNullOrEmpty(node.options.Platform))
node.options.Platform = options.SolutionPlatform;
// copy properties to project options
options.GlobalAdditionalProperties.ForEach(node.options.Properties.Add);
if (project == rootProject) {
foreach (var pair in options.ProjectAdditionalProperties) {
node.options.Properties[pair.Key] = pair.Value;
}
}
node.options = project.CreateProjectBuildOptions(options, project == rootProject);
}
void InitializeDependencies(BuildNode node)

52
src/Main/Base/Project/Src/Project/IProject.cs

@ -272,6 +272,58 @@ namespace ICSharpCode.SharpDevelop.Project @@ -272,6 +272,58 @@ namespace ICSharpCode.SharpDevelop.Project
Solution ParentSolution { get; }
}
// We cannot extend an existing interface in 3.x because we don't want to break addin compatibility.
// TODO: merge this interface with IBuildable in SharpDevelop 4.0
public interface IBuildable2 : IBuildable
{
/// <summary>
/// Creates the project-specific build options.
/// </summary>
/// <param name="options">The global build options.</param>
/// <param name="isRootBuildable">Specifies whether this project is the main buildable item
/// (i.e. the ).</param>
/// <returns>The project-specific build options.</returns>
ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable);
}
/// <summary>
/// Provides the IBuildable2 methods in IBuildable.
/// For classes not implementing IBuildable2, a default implementation is used.
/// </summary>
public static class IBuildableExtension
{
public static ProjectBuildOptions CreateProjectBuildOptions(this IBuildable buildable, BuildOptions options, bool isRootBuildable)
{
IBuildable2 buildable2 = buildable as IBuildable2;
if (buildable2 != null) {
return buildable2.CreateProjectBuildOptions(options, isRootBuildable);
}
// start of default implementation
var configMatchings = buildable.ParentSolution.GetActiveConfigurationsAndPlatformsForProjects(options.SolutionConfiguration, options.SolutionPlatform);
ProjectBuildOptions projectOptions = new ProjectBuildOptions(isRootBuildable ? options.ProjectTarget : options.TargetForDependencies);
// find the project configuration
foreach (var matching in configMatchings) {
if (matching.Project == buildable) {
projectOptions.Configuration = matching.Configuration;
projectOptions.Platform = matching.Platform;
}
}
if (string.IsNullOrEmpty(projectOptions.Configuration))
projectOptions.Configuration = options.SolutionConfiguration;
if (string.IsNullOrEmpty(projectOptions.Platform))
projectOptions.Platform = options.SolutionPlatform;
// copy properties to project options
options.GlobalAdditionalProperties.ForEach(projectOptions.Properties.Add);
if (isRootBuildable) {
foreach (var pair in options.ProjectAdditionalProperties) {
projectOptions.Properties[pair.Key] = pair.Value;
}
}
return projectOptions;
}
}
/// <summary>
/// Interface for adding and removing items from a project. Not part of the IProject
/// interface because in nearly all cases, ProjectService.Add/RemoveProjectItem should

14
src/Main/Base/Project/Src/Services/ProjectService/CompileModifiedProjectsOnly.cs

@ -118,7 +118,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -118,7 +118,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
sealed class DummyBuildable : IBuildable
sealed class DummyBuildable : IBuildable2
{
IBuildable wrappedBuildable;
@ -135,6 +135,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -135,6 +135,11 @@ namespace ICSharpCode.SharpDevelop.Project
get { return wrappedBuildable.ParentSolution; }
}
public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)
{
return null;
}
public ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
{
return new IBuildable[0];
@ -178,7 +183,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -178,7 +183,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
sealed class Wrapper : IBuildable
sealed class Wrapper : IBuildable2
{
internal readonly IBuildable wrapped;
internal readonly WrapperFactory factory;
@ -197,6 +202,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -197,6 +202,11 @@ namespace ICSharpCode.SharpDevelop.Project
get { return wrapped.ParentSolution; }
}
public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)
{
return wrapped.CreateProjectBuildOptions(options, isRootBuildable);
}
Dictionary<ProjectBuildOptions, ICollection<IBuildable>> cachedBuildDependencies = new Dictionary<ProjectBuildOptions, ICollection<IBuildable>>();
public ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)

5
src/Main/ICSharpCode.SharpDevelop.BuildWorker/Interprocess/HostProcess.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess @@ -41,7 +41,7 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess
internal const int SendKeepAliveInterval = 10000;
public void WorkerProcessMain(string argument)
public void WorkerProcessMain(string argument, string passwordBase64)
{
int port = int.Parse(argument, CultureInfo.InvariantCulture);
@ -55,6 +55,9 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess @@ -55,6 +55,9 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess
receiver.PacketReceived += OnPacketReceived;
sender.WriteFailed += OnConnectionLost;
// send password
sender.Send(Convert.FromBase64String(passwordBase64));
receiver.StartReceive(stream);
while (!shutdownEvent.WaitOne(SendKeepAliveInterval, false)) {
Program.Log("Sending keep-alive packet");

50
src/Main/ICSharpCode.SharpDevelop.BuildWorker/Interprocess/WorkerProcess.cs

@ -7,14 +7,15 @@ @@ -7,14 +7,15 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Net;
using System.Globalization;
using System.Net.Sockets;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Threading;
namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess
@ -41,17 +42,31 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess @@ -41,17 +42,31 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess
PacketSender sender;
PacketReceiver receiver;
// We use TCP, so we'll have to deal with "attackers" trying to hijack our connection.
// There are two lines of defense:
// 1. the only local connections are accepted
// 2. the client must authenticate with a random password
// We're not protecting against DOS - we're only vulnerable to local attackers during a short
// time frame. The password is only to defend against deserializing arbitrary objects from
// unauthenticated clients.
// We probably should use Named Pipes instead of TCP.
byte[] password;
bool clientAuthenticated;
public void Start(ProcessStartInfo info)
{
if (info == null)
throw new ArgumentNullException("info");
password = new byte[16];
new RNGCryptoServiceProvider().GetBytes(password);
listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
string argument = ((IPEndPoint)listener.LocalEndpoint).Port.ToString(CultureInfo.InvariantCulture);
string oldArguments = info.Arguments;
info.Arguments += " " + argument;
info.Arguments += " " + argument + " " + Convert.ToBase64String(password);
process = Process.Start(info);
// "manual process start" - useful for profiling the build worker
//System.Windows.Forms.MessageBox.Show(info.Arguments);
@ -91,6 +106,7 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess @@ -91,6 +106,7 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess
void OnAcceptTcpClient(IAsyncResult ar)
{
clientAuthenticated = false;
SetTimeout();
try {
client = listener.EndAcceptTcpClient(ar);
@ -134,9 +150,29 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess @@ -134,9 +150,29 @@ namespace ICSharpCode.SharpDevelop.BuildWorker.Interprocess
{
SetTimeout();
if (e.Packet.Length != 0) {
MethodCall mc = (MethodCall)DeserializeObject(e.Packet);
mc.CallOn(hostObject);
if (clientAuthenticated) {
MethodCall mc = (MethodCall)DeserializeObject(e.Packet);
mc.CallOn(hostObject);
} else {
if (ArrayEquals(e.Packet, password)) {
clientAuthenticated = true;
} else {
Kill();
throw new InvalidOperationException("Worker process authentication failed.");
}
}
}
}
static bool ArrayEquals(byte[] a, byte[] b)
{
if (a.Length != b.Length)
return false;
for (int i = 0; i < a.Length; i++) {
if (a[i] != b[i])
return false;
}
return true;
}
public void Kill()

4
src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs

@ -32,10 +32,10 @@ namespace ICSharpCode.SharpDevelop.BuildWorker @@ -32,10 +32,10 @@ namespace ICSharpCode.SharpDevelop.BuildWorker
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(AppDomain_CurrentDomain_UnhandledException);
if (args.Length == 2 && args[0] == "worker") {
if (args.Length == 3 && args[0] == "worker") {
try {
host = new HostProcess(new Program());
host.WorkerProcessMain(args[1]);
host.WorkerProcessMain(args[1], args[2]);
} catch (Exception ex) {
ShowMessageBox(ex.ToString());
}

Loading…
Cancel
Save