public Task<MSBuildResult> Run ( ProjectConfigurationInfo[] configurations, ILogWriter logWriter, MSBuildVerbosity verbosity, string[] runTargets, string[] evaluateItems, string[] evaluateProperties, Dictionary<string, string> globalProperties, CancellationToken cancellationToken ) { // Get an id for the task, and get ready to cancel it if the cancellation token is signalled var taskId = Interlocked.Increment (ref lastTaskId); var cr = RegisterCancellation (cancellationToken, taskId); var t = Task.Run (() => { try { BeginOperation (); var res = builder.Run (configurations, logWriter, verbosity, runTargets, evaluateItems, evaluateProperties, globalProperties, taskId); if (res == null && cancellationToken.IsCancellationRequested) { MSBuildTargetResult err = new MSBuildTargetResult (file, false, "", "", file, 1, 1, 1, 1, "Build cancelled", ""); return new MSBuildResult (new [] { err }); } if (res == null) throw new Exception ("Unknown failure"); return res; } catch (Exception ex) { CheckDisconnected (); LoggingService.LogError ("RunTarget failed", ex); MSBuildTargetResult err = new MSBuildTargetResult (file, false, "", "", file, 1, 1, 1, 1, "Unknown MSBuild failure. Please try building the project again", ""); MSBuildResult res = new MSBuildResult (new [] { err }); return res; } finally { EndOperation (); } }); // Dispose the cancel registration t.ContinueWith (r => cr.Dispose ()); return t; }
public async Task<AssemblyReference[]> ResolveAssemblyReferences (ProjectConfigurationInfo[] configurations, CancellationToken cancellationToken) { AssemblyReference[] refs = null; var id = configurations [0].Configuration + "|" + configurations [0].Platform; using (await referenceCacheLock.EnterAsync ()) { // Check the cache before starting the task if (referenceCache.TryGetValue (id, out refs)) return refs; } // Get an id for the task, it will be used later on to cancel the task if necessary var taskId = Interlocked.Increment (ref lastTaskId); IDisposable cr = null; refs = await Task.Run (async () => { using (await referenceCacheLock.EnterAsync ()) { // Check again the cache, maybe the value was set while the task was starting if (referenceCache.TryGetValue (id, out refs)) return refs; // Get ready to cancel the task if the cancellation token is signalled cr = RegisterCancellation (cancellationToken, taskId); MSBuildResult result; bool locked = false; try { BeginOperation (); locked = await engine.Semaphore.WaitAsync (Timeout.Infinite, cancellationToken).ConfigureAwait (false); // FIXME: This lock should not be necessary, but remoting seems to have problems when doing many concurrent calls. result = builder.Run ( configurations, null, MSBuildVerbosity.Normal, new [] { "ResolveAssemblyReferences" }, new [] { "ReferencePath" }, null, null, taskId ); } catch (Exception ex) { CheckDisconnected (); LoggingService.LogError ("ResolveAssemblyReferences failed", ex); return new AssemblyReference [0]; } finally { if (locked) engine.Semaphore.Release (); EndOperation (); } List<MSBuildEvaluatedItem> items; if (result.Items.TryGetValue ("ReferencePath", out items) && items != null) { string aliases; refs = items.Select (i => new AssemblyReference (i.ItemSpec, i.Metadata.TryGetValue ("Aliases", out aliases) ? aliases : "")).ToArray (); } else refs = new AssemblyReference [0]; referenceCache [id] = refs; } return refs; }); // Dispose the cancel registration if (cr != null) cr.Dispose (); return refs; }
public MSBuildResult Run ( ProjectConfigurationInfo[] configurations, ILogWriter logWriter, MSBuildVerbosity verbosity, string[] runTargets, string[] evaluateItems, string[] evaluateProperties, Dictionary<string,string> globalProperties, int taskId) { MSBuildResult result = null; BuildEngine.RunSTA (taskId, delegate { try { var project = SetupProject (configurations); InitLogger (logWriter); buildEngine.Engine.UnregisterAllLoggers (); var logger = new LocalLogger (file); buildEngine.Engine.RegisterLogger (logger); if (logWriter != null) { buildEngine.Engine.RegisterLogger (consoleLogger); consoleLogger.Verbosity = GetVerbosity (verbosity); } if (runTargets != null && runTargets.Length > 0) { if (globalProperties != null) { foreach (var p in globalProperties) project.GlobalProperties.SetProperty (p.Key, p.Value); } // We are using this BuildProject overload and the BuildSettings.None argument as a workaround to // an xbuild bug which causes references to not be resolved after the project has been built once. buildEngine.Engine.BuildProject (project, runTargets, new Hashtable (), BuildSettings.None); if (globalProperties != null) { foreach (var p in globalProperties.Keys) { project.GlobalProperties.RemoveProperty (p); buildEngine.Engine.GlobalProperties.RemoveProperty (p); } } } result = new MSBuildResult (logger.BuildResult.ToArray ()); if (evaluateProperties != null) { foreach (var name in evaluateProperties) result.Properties [name] = project.GetEvaluatedProperty (name); } if (evaluateItems != null) { foreach (var name in evaluateItems) { BuildItemGroup grp = project.GetEvaluatedItemsByName (name); var list = new List<MSBuildEvaluatedItem> (); foreach (BuildItem item in grp) { var evItem = new MSBuildEvaluatedItem (name, UnescapeString (item.FinalItemSpec)); foreach (DictionaryEntry de in (IDictionary) evaluatedMetadataField.GetValue (item)) { evItem.Metadata [(string)de.Key] = UnescapeString ((string)de.Value); } list.Add (evItem); } result.Items[name] = list; } } } catch (InvalidProjectFileException ex) { var r = new MSBuildTargetResult ( file, false, ex.ErrorSubcategory, ex.ErrorCode, ex.ProjectFile, ex.LineNumber, ex.ColumnNumber, ex.EndLineNumber, ex.EndColumnNumber, ex.BaseMessage, ex.HelpKeyword); LogWriteLine (r.ToString ()); result = new MSBuildResult (new [] { r }); } finally { DisposeLogger (); } }); return result; }
Project SetupProject (ProjectConfigurationInfo[] configurations) { Project project = null; var slnConfigContents = GenerateSolutionConfigurationContents (configurations); foreach (var pc in configurations) { var p = buildEngine.Engine.GetLoadedProject (pc.ProjectFile); if (p != null && pc.ProjectFile == file) { // building the project may create new items and/or modify some properties, // so we always need to use a new instance of the project when building buildEngine.Engine.UnloadProject (p); p = null; } Environment.CurrentDirectory = Path.GetDirectoryName (Path.GetFullPath (file)); if (p == null) { p = new Project (buildEngine.Engine); var content = buildEngine.GetUnsavedProjectContent (pc.ProjectFile); if (content == null) { p.Load (pc.ProjectFile); } else { p.FullFileName = Path.GetFullPath (pc.ProjectFile); if (HasXbuildFileBug ()) { // Workaround for Xamarin bug #14295: Project.Load incorrectly resets the FullFileName property var t = p.GetType (); t.InvokeMember ("PushThisFileProperty", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, p, new object[] { p.FullFileName }); t.InvokeMember ("DoLoad", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, p, new object[] { new StringReader (content) }); } else { p.Load (new StringReader (content)); } } } p.GlobalProperties.SetProperty ("CurrentSolutionConfigurationContents", slnConfigContents); p.GlobalProperties.SetProperty ("Configuration", pc.Configuration); if (!string.IsNullOrEmpty (pc.Platform)) p.GlobalProperties.SetProperty ("Platform", pc.Platform); else p.GlobalProperties.RemoveProperty ("Platform"); if (pc.ProjectFile == file) project = p; } Environment.CurrentDirectory = Path.GetDirectoryName (Path.GetFullPath (file)); return project; }
string GenerateSolutionConfigurationContents (ProjectConfigurationInfo[] configurations) { // can't use XDocument because of the 2.0 builder // and don't just build a string because things may need escaping var doc = new XmlDocument (); var root = doc.CreateElement ("SolutionConfiguration"); doc.AppendChild (root); foreach (var config in configurations) { var el = doc.CreateElement ("ProjectConfiguration"); root.AppendChild (el); el.SetAttribute ("Project", config.ProjectGuid); el.SetAttribute ("AbsolutePath", config.ProjectFile); el.SetAttribute ("BuildProjectInSolution", config.Enabled ? "True" : "False"); el.InnerText = string.Format (config.Configuration + "|" + config.Platform); } //match MSBuild formatting var options = new XmlWriterSettings { Indent = true, IndentChars = "", OmitXmlDeclaration = true, }; using (var sw = new StringWriter ()) using (var xw = XmlWriter.Create (sw, options)) { doc.WriteTo (xw); xw.Flush (); return sw.ToString (); } }
public MSBuildResult Run ( ProjectConfigurationInfo[] configurations, ILogWriter logWriter, MSBuildVerbosity verbosity, string[] runTargets, string[] evaluateItems, string[] evaluateProperties, Dictionary<string,string> globalProperties, int taskId) { if (runTargets == null || runTargets.Length == 0) throw new ArgumentException ("runTargets is empty"); MSBuildResult result = null; BuildEngine.RunSTA (taskId, delegate { try { var project = SetupProject (configurations); InitLogger (logWriter); ILogger[] loggers; var logger = new LocalLogger (file); if (logWriter != null) { var consoleLogger = new ConsoleLogger (GetVerbosity (verbosity), LogWriteLine, null, null); loggers = new ILogger[] { logger, consoleLogger }; } else { loggers = new ILogger[] { logger }; } //building the project will create items and alter properties, so we use a new instance var pi = project.CreateProjectInstance (); if (globalProperties != null) foreach (var p in globalProperties) pi.SetProperty (p.Key, p.Value); pi.Build (runTargets, loggers); result = new MSBuildResult (logger.BuildResult.ToArray ()); if (evaluateProperties != null) { foreach (var name in evaluateProperties) { var prop = pi.GetProperty (name); result.Properties [name] = prop != null? prop.EvaluatedValue : null; } } if (evaluateItems != null) { foreach (var name in evaluateItems) { var grp = pi.GetItems (name); var list = new List<MSBuildEvaluatedItem> (); foreach (var item in grp) { var evItem = new MSBuildEvaluatedItem (name, UnescapeString (item.EvaluatedInclude)); foreach (var m in item.Metadata) { evItem.Metadata [m.Name] = UnescapeString (m.EvaluatedValue); } list.Add (evItem); } result.Items[name] = list; } } } catch (Microsoft.Build.Exceptions.InvalidProjectFileException ex) { var r = new MSBuildTargetResult ( file, false, ex.ErrorSubcategory, ex.ErrorCode, ex.ProjectFile, ex.LineNumber, ex.ColumnNumber, ex.EndLineNumber, ex.EndColumnNumber, ex.BaseMessage, ex.HelpKeyword); LogWriteLine (r.ToString ()); result = new MSBuildResult (new [] { r }); } finally { DisposeLogger (); } }); return result; }
Project SetupProject (ProjectConfigurationInfo[] configurations) { Project project = null; var slnConfigContents = GenerateSolutionConfigurationContents (configurations); foreach (var pc in configurations) { var p = ConfigureProject (pc.ProjectFile, pc.Configuration, pc.Platform, slnConfigContents); if (pc.ProjectFile == file) project = p; } Environment.CurrentDirectory = Path.GetDirectoryName (file); return project; }