~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/Main/Base/Project/Src/Project/MSBuildInternals.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Collections.Generic;
 
6
using System.Linq;
 
7
using System.Text.RegularExpressions;
 
8
 
 
9
using ICSharpCode.Core;
 
10
using Microsoft.Build.Construction;
 
11
using Microsoft.Build.Execution;
 
12
using Microsoft.Build.Framework;
 
13
using MSBuild = Microsoft.Build;
 
14
using ProjectCollection = Microsoft.Build.Evaluation.ProjectCollection;
 
15
 
 
16
namespace ICSharpCode.SharpDevelop.Project
 
17
{
 
18
        /// <summary>
 
19
        /// Messing with MSBuild's internals.
 
20
        /// </summary>
 
21
        public static class MSBuildInternals
 
22
        {
 
23
                /// <summary>
 
24
                /// SharpDevelop uses one project collection per solution.
 
25
                /// Code accessing one of those collection (even if indirectly through MSBuild) should lock on
 
26
                /// MSBuildInternals.SolutionProjectCollectionLock.
 
27
                /// </summary>
 
28
                public readonly static object SolutionProjectCollectionLock = new object();
 
29
                
 
30
                // TODO: I think MSBuild actually uses OrdinalIgnoreCase. SharpDevelop 3.x just used string.operator ==, so I'm keeping
 
31
                // that setting until all code is ported to use PropertyNameComparer and we've verified what MSBuild is actually using.
 
32
                public readonly static StringComparer PropertyNameComparer = StringComparer.Ordinal;
 
33
                
 
34
                internal static void UnloadProject(MSBuild.Evaluation.ProjectCollection projectCollection, MSBuild.Evaluation.Project project)
 
35
                {
 
36
                        lock (SolutionProjectCollectionLock) {
 
37
                                projectCollection.UnloadProject(project);
 
38
                        }
 
39
                }
 
40
                
 
41
                internal static MSBuild.Evaluation.Project LoadProject(MSBuild.Evaluation.ProjectCollection projectCollection, ProjectRootElement rootElement, IDictionary<string, string> globalProps)
 
42
                {
 
43
                        lock (SolutionProjectCollectionLock) {
 
44
                                string toolsVersion = rootElement.ToolsVersion;
 
45
                                if (string.IsNullOrEmpty(toolsVersion))
 
46
                                        toolsVersion = projectCollection.DefaultToolsVersion;
 
47
                                return new MSBuild.Evaluation.Project(rootElement, globalProps, toolsVersion, projectCollection);
 
48
                        }
 
49
                }
 
50
                
 
51
                internal static ProjectInstance LoadProjectInstance(MSBuild.Evaluation.ProjectCollection projectCollection, ProjectRootElement rootElement, IDictionary<string, string> globalProps)
 
52
                {
 
53
                        lock (SolutionProjectCollectionLock) {
 
54
                                string toolsVersion = rootElement.ToolsVersion;
 
55
                                if (string.IsNullOrEmpty(toolsVersion))
 
56
                                        toolsVersion = projectCollection.DefaultToolsVersion;
 
57
                                return new ProjectInstance(rootElement, globalProps, toolsVersion, projectCollection);
 
58
                        }
 
59
                }
 
60
                
 
61
                public const string MSBuildXmlNamespace = "http://schemas.microsoft.com/developer/msbuild/2003";
 
62
                
 
63
                #region Escaping
 
64
                /// <summary>
 
65
                /// Escapes special MSBuild characters ( '%', '*', '?', '@', '$', '(', ')', ';', "'" ).
 
66
                /// </summary>
 
67
                public static string Escape(string text)
 
68
                {
 
69
                        return MSBuild.Evaluation.ProjectCollection.Escape(text);
 
70
                }
 
71
                
 
72
                /// <summary>
 
73
                /// Unescapes escaped MSBuild characters.
 
74
                /// </summary>
 
75
                public static string Unescape(string text)
 
76
                {
 
77
                        return MSBuild.Evaluation.ProjectCollection.Unescape(text);
 
78
                }
 
79
                #endregion
 
80
                
 
81
                /// <summary>
 
82
                /// This is a special case in MSBuild we need to take care of.
 
83
                /// </summary>
 
84
                public static string FixPlatformNameForProject(string platformName)
 
85
                {
 
86
                        if (platformName == "Any CPU") {
 
87
                                return "AnyCPU";
 
88
                        } else {
 
89
                                return platformName;
 
90
                        }
 
91
                }
 
92
                
 
93
                /// <summary>
 
94
                /// This is a special case in MSBuild we need to take care of.
 
95
                /// Opposite of FixPlatformNameForProject
 
96
                /// </summary>
 
97
                public static string FixPlatformNameForSolution(string platformName)
 
98
                {
 
99
                        if (platformName == "AnyCPU") {
 
100
                                return "Any CPU";
 
101
                        } else {
 
102
                                return platformName;
 
103
                        }
 
104
                }
 
105
                
 
106
                internal static PropertyStorageLocations GetLocationFromCondition(MSBuild.Construction.ProjectElement element)
 
107
                {
 
108
                        while (element != null) {
 
109
                                if (!string.IsNullOrEmpty(element.Condition))
 
110
                                        return GetLocationFromCondition(element.Condition);
 
111
                                element = element.Parent;
 
112
                        }
 
113
                        return PropertyStorageLocations.Base;
 
114
                }
 
115
                
 
116
                internal static PropertyStorageLocations GetLocationFromCondition(string condition)
 
117
                {
 
118
                        if (string.IsNullOrEmpty(condition)) {
 
119
                                return PropertyStorageLocations.Base;
 
120
                        }
 
121
                        PropertyStorageLocations location = 0; // 0 is unknown
 
122
                        if (condition.Contains("$(Configuration)"))
 
123
                                location |= PropertyStorageLocations.ConfigurationSpecific;
 
124
                        if (condition.Contains("$(Platform)"))
 
125
                                location |= PropertyStorageLocations.PlatformSpecific;
 
126
                        return location;
 
127
                }
 
128
                
 
129
                readonly static Regex configurationRegEx = new Regex(@"'(?<property>[^']*)'\s*==\s*'(?<value>[^']*)'", RegexOptions.Compiled);
 
130
                
 
131
                internal static void GetConfigurationAndPlatformFromCondition(string condition,
 
132
                                                                              out string configuration,
 
133
                                                                              out string platform)
 
134
                {
 
135
                        Match match = configurationRegEx.Match(condition);
 
136
                        if (match.Success) {
 
137
                                string conditionProperty = match.Result("${property}");
 
138
                                string conditionValue = match.Result("${value}");
 
139
                                if (conditionProperty == "$(Configuration)|$(Platform)") {
 
140
                                        // configuration is ok
 
141
                                        configuration = MSBuildBasedProject.GetConfigurationNameFromKey(conditionValue);
 
142
                                        platform = MSBuildBasedProject.GetPlatformNameFromKey(conditionValue);
 
143
                                } else if (conditionProperty == "$(Configuration)") {
 
144
                                        configuration = conditionValue;
 
145
                                        platform = null;
 
146
                                } else if (conditionProperty == "$(Platform)") {
 
147
                                        configuration = null;
 
148
                                        platform = conditionValue;
 
149
                                } else {
 
150
                                        configuration = null;
 
151
                                        platform = null;
 
152
                                }
 
153
                        } else {
 
154
                                configuration = null;
 
155
                                platform = null;
 
156
                        }
 
157
                }
 
158
                
 
159
                /// <summary>
 
160
                /// Resolves the location of the reference files.
 
161
                /// </summary>
 
162
                /// <param name="baseProject">The base project.</param>
 
163
                /// <param name="referenceReplacements">A different set of references to use instead of those in the project.
 
164
                /// Used by the GacReferencePanel.</param>
 
165
                internal static void ResolveAssemblyReferences(MSBuildBasedProject baseProject, ReferenceProjectItem[] referenceReplacements)
 
166
                {
 
167
                        ProjectInstance project = baseProject.CreateProjectInstance();
 
168
                        project.SetProperty("BuildingProject", "false");
 
169
                        
 
170
                        List<ProjectItemInstance> references = (
 
171
                                from item in project.Items
 
172
                                where ItemType.ReferenceItemTypes.Contains(new ItemType(item.ItemType))
 
173
                                select item
 
174
                        ).ToList();
 
175
                        
 
176
                        ReferenceProjectItem[] referenceProjectItems;
 
177
                        
 
178
                        if (referenceReplacements == null) {
 
179
                                // Remove the "Private" meta data.
 
180
                                // This is necessary to detect the default value for "Private"
 
181
                                foreach (ProjectItemInstance reference in references) {
 
182
                                        reference.RemoveMetadata("Private");
 
183
                                }
 
184
                                
 
185
                                referenceProjectItems = baseProject.Items.OfType<ReferenceProjectItem>().ToArray();
 
186
                        } else {
 
187
                                foreach (ProjectItemInstance reference in references) {
 
188
                                        project.RemoveItem(reference);
 
189
                                }
 
190
                                foreach (ReferenceProjectItem item in referenceReplacements) {
 
191
                                        project.AddItem("Reference", item.Include);
 
192
                                }
 
193
                                referenceProjectItems = referenceReplacements;
 
194
                        }
 
195
                        
 
196
                        string[] targets = { "ResolveAssemblyReferences" };
 
197
                        BuildRequestData requestData = new BuildRequestData(project, targets, new HostServices());
 
198
                        List<ILogger> loggers = new List<ILogger>();
 
199
                        if (referenceReplacements == null)
 
200
                                loggers.Add(new SimpleErrorLogger());
 
201
                        lock (SolutionProjectCollectionLock) {
 
202
                                BuildParameters parameters = new BuildParameters(baseProject.MSBuildProjectCollection);
 
203
                                parameters.Loggers = loggers;
 
204
                                
 
205
                                LoggingService.Debug("Started build for ResolveAssemblyReferences");
 
206
                                BuildResult result = BuildManager.DefaultBuildManager.Build(parameters, requestData);
 
207
                                if (result == null)
 
208
                                        throw new InvalidOperationException("BuildResult is null");
 
209
                                LoggingService.Debug("Build for ResolveAssemblyReferences finished: " + result.OverallResult);
 
210
                        }
 
211
                        
 
212
                        var referenceDict = new Dictionary<string, ReferenceProjectItem>();
 
213
                        foreach (ReferenceProjectItem item in referenceProjectItems) {
 
214
                                // references could be duplicate, so we cannot use referenceDict.Add or reference.ToDictionary
 
215
                                referenceDict[item.Include] = item;
 
216
                        }
 
217
                        
 
218
                        
 
219
                        foreach (ProjectItemInstance item in project.GetItems("_ResolveAssemblyReferenceResolvedFiles")) {
 
220
                                string originalInclude = item.GetMetadataValue("OriginalItemSpec");
 
221
                                ReferenceProjectItem reference;
 
222
                                if (referenceDict.TryGetValue(originalInclude, out reference)) {
 
223
                                        reference.AssemblyName = new Dom.DomAssemblyName(item.GetMetadataValue("FusionName"));
 
224
                                        //string fullPath = item.GetEvaluatedMetadata("FullPath"); is incorrect for relative paths
 
225
                                        string fullPath = FileUtility.GetAbsolutePath(baseProject.Directory, item.GetMetadataValue("Identity"));
 
226
                                        reference.FileName = fullPath;
 
227
                                        reference.Redist = item.GetMetadataValue("Redist");
 
228
                                        LoggingService.Debug("Got information about " + originalInclude + "; fullpath=" + fullPath);
 
229
                                        reference.DefaultCopyLocalValue = bool.Parse(item.GetMetadataValue("CopyLocal"));
 
230
                                } else {
 
231
                                        LoggingService.Warn("Unknown item " + originalInclude);
 
232
                                }
 
233
                        }
 
234
                }
 
235
                
 
236
                sealed class SimpleErrorLogger : ILogger
 
237
                {
 
238
                        #region ILogger interface implementation
 
239
                        public LoggerVerbosity Verbosity { get; set; }
 
240
                        public string Parameters { get; set; }
 
241
                        
 
242
                        public void Initialize(IEventSource eventSource)
 
243
                        {
 
244
                                eventSource.ErrorRaised += OnError;
 
245
                                eventSource.WarningRaised += OnWarning;
 
246
                        }
 
247
                        
 
248
                        public void Shutdown()
 
249
                        {
 
250
                        }
 
251
                        #endregion
 
252
                        
 
253
                        void OnError(object sender, BuildErrorEventArgs e)
 
254
                        {
 
255
                                TaskService.BuildMessageViewCategory.AppendLine(e.Message);
 
256
                        }
 
257
                        
 
258
                        void OnWarning(object sender, BuildWarningEventArgs e)
 
259
                        {
 
260
                                TaskService.BuildMessageViewCategory.AppendLine(e.Message);
 
261
                        }
 
262
                }
 
263
        }
 
264
}