aboutsummaryrefslogtreecommitdiff
path: root/src/wix/WixToolset.BuildTasks/UpdateProjectReferenceMetadata.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/wix/WixToolset.BuildTasks/UpdateProjectReferenceMetadata.cs')
-rw-r--r--src/wix/WixToolset.BuildTasks/UpdateProjectReferenceMetadata.cs466
1 files changed, 374 insertions, 92 deletions
diff --git a/src/wix/WixToolset.BuildTasks/UpdateProjectReferenceMetadata.cs b/src/wix/WixToolset.BuildTasks/UpdateProjectReferenceMetadata.cs
index c1ef45bc..d391bdb9 100644
--- a/src/wix/WixToolset.BuildTasks/UpdateProjectReferenceMetadata.cs
+++ b/src/wix/WixToolset.BuildTasks/UpdateProjectReferenceMetadata.cs
@@ -6,15 +6,16 @@ namespace WixToolset.BuildTasks
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.IO; 7 using System.IO;
8 using System.Linq; 8 using System.Linq;
9 using System.Text;
9 using Microsoft.Build.Framework; 10 using Microsoft.Build.Framework;
10 using Microsoft.Build.Utilities; 11 using Microsoft.Build.Utilities;
11 12
12 /// <summary> 13 /// <summary>
13 /// This task adds publish metadata to the appropriate project references. 14 /// This task adds mutli-targeting and publish metadata to the appropriate project references.
14 /// </summary> 15 /// </summary>
15 public class UpdateProjectReferenceMetadata : Task 16 public class UpdateProjectReferenceMetadata : Task
16 { 17 {
17 private static readonly char[] TargetFrameworksSplitter = new char[] { ',', ';' }; 18 private static readonly char[] MetadataPairSplitter = new char[] { '|' };
18 19
19 /// <summary> 20 /// <summary>
20 /// The list of project references that exist. 21 /// The list of project references that exist.
@@ -29,168 +30,449 @@ namespace WixToolset.BuildTasks
29 public ITaskItem[] UpdatedProjectReferences { get; private set; } 30 public ITaskItem[] UpdatedProjectReferences { get; private set; }
30 31
31 /// <summary> 32 /// <summary>
32 /// Finds all project references requesting publishing and updates them to publish instead of build and 33 /// Finds all project references requesting multi-targeting and publishing and updates them to publish instead of build and
33 /// sets target framework if requested. 34 /// sets target framework if requested.
34 /// </summary> 35 /// </summary>
35 /// <returns>True upon completion of the task execution.</returns> 36 /// <returns>True upon completion of the task execution.</returns>
36 public override bool Execute() 37 public override bool Execute()
37 { 38 {
38 var updatedProjectReferences = new List<ITaskItem>();
39 var intermediateFolder = Path.GetFullPath(this.IntermediateFolder); 39 var intermediateFolder = Path.GetFullPath(this.IntermediateFolder);
40 40
41 foreach (var projectReference in this.ProjectReferences) 41 // Create the project reference facades.
42 { 42 var projectReferenceFacades = this.ProjectReferences.Select(p => ProjectReferenceFacade.CreateFacade(p, this.Log, intermediateFolder));
43 var additionalProjectReferences = new List<ITaskItem>(); 43
44 // Expand the facade count by applying Configurations/Platforms.
45 projectReferenceFacades = this.ExpandProjectReferencesForConfigurationsAndPlatforms(projectReferenceFacades);
46
47 // Expand the facade count by applying TargetFrameworks/RuntimeIdentifiers.
48 projectReferenceFacades = this.ExpandProjectReferencesForTargetFrameworksAndRuntimeIdentifiers(projectReferenceFacades);
44 49
45 var updatedProjectReference = this.TrySetTargetFrameworksOnProjectReference(projectReference, additionalProjectReferences); 50 // Assign any metadata added during expansion above to the project references.
51 this.UpdatedProjectReferences = this.AssignMetadataToProjectReferences(projectReferenceFacades).ToArray();
52
53 return true;
54 }
46 55
47 if (this.TryAddPublishPropertiesToProjectReference(projectReference, intermediateFolder)) 56 private IEnumerable<ProjectReferenceFacade> ExpandProjectReferencesForConfigurationsAndPlatforms(IEnumerable<ProjectReferenceFacade> projectReferenceFacades)
57 {
58 foreach (var projectReferenceFacade in projectReferenceFacades)
59 {
60 var configurationsWithPlatforms = ExpandTerms(projectReferenceFacade.AvailableConfigurations, projectReferenceFacade.AvailablePlatforms).ToList();
61
62 if (configurationsWithPlatforms.Count == 0)
63 {
64 yield return projectReferenceFacade;
65 }
66 else
48 { 67 {
49 foreach (var additionalProjectReference in additionalProjectReferences) 68 var expand = new List<ProjectReferenceFacade>(configurationsWithPlatforms.Count)
50 { 69 {
51 this.TryAddPublishPropertiesToProjectReference(additionalProjectReference, intermediateFolder); 70 projectReferenceFacade
71 };
72
73 // First, clone the project reference so there are enough facades for all of the
74 // requested configurations/platforms.
75 for (var i = 1; i < configurationsWithPlatforms.Count; ++i)
76 {
77 expand.Add(projectReferenceFacade.Clone());
52 } 78 }
53 79
54 updatedProjectReference = true; 80 // Then set the configuration/platform on each project reference.
81 for (var i = 0; i < configurationsWithPlatforms.Count; ++i)
82 {
83 expand[i].Configuration = configurationsWithPlatforms[i].FirstTerm;
84 expand[i].Platform = configurationsWithPlatforms[i].SecondTerm;
85
86 yield return expand[i];
87 }
55 } 88 }
89 }
90 }
91
92 private IEnumerable<ProjectReferenceFacade> ExpandProjectReferencesForTargetFrameworksAndRuntimeIdentifiers(IEnumerable<ProjectReferenceFacade> projectReferenceFacades)
93 {
94 foreach (var projectReferenceFacade in projectReferenceFacades)
95 {
96 var tfmsWithRids = ExpandTerms(projectReferenceFacade.AvailableTargetFrameworks, projectReferenceFacade.AvailableRuntimeIdentifiers).ToList();
56 97
57 if (updatedProjectReference) 98 if (tfmsWithRids.Count == 0)
58 { 99 {
59 updatedProjectReferences.Add(projectReference); 100 yield return projectReferenceFacade;
60 } 101 }
102 else
103 {
104 var expand = new List<ProjectReferenceFacade>(tfmsWithRids.Count)
105 {
106 projectReferenceFacade
107 };
61 108
62 updatedProjectReferences.AddRange(additionalProjectReferences); 109 // First, clone the project reference so there are enough facades for all of the
63 } 110 // requested target frameworks/runtime identifiers.
111 for (var i = 1; i < tfmsWithRids.Count; ++i)
112 {
113 expand.Add(projectReferenceFacade.Clone());
114 }
64 115
65 this.UpdatedProjectReferences = updatedProjectReferences.ToArray(); 116 // Then set the target framework/runtime identifier on each project reference.
117 for (var i = 0; i < tfmsWithRids.Count; ++i)
118 {
119 expand[i].TargetFramework = tfmsWithRids[i].FirstTerm;
120 expand[i].RuntimeIdentifier = tfmsWithRids[i].SecondTerm;
66 121
67 return true; 122 yield return expand[i];
123 }
124 }
125 }
68 } 126 }
69 127
70 private bool TryAddPublishPropertiesToProjectReference(ITaskItem projectReference, string intermediateFolder) 128 private IEnumerable<ITaskItem> AssignMetadataToProjectReferences(IEnumerable<ProjectReferenceFacade> facades)
71 { 129 {
72 var publish = projectReference.GetMetadata("Publish"); 130 foreach (var facade in facades)
73 var publishDir = projectReference.GetMetadata("PublishDir");
74
75 if (publish.Equals("true", StringComparison.OrdinalIgnoreCase) ||
76 (String.IsNullOrWhiteSpace(publish) && !String.IsNullOrWhiteSpace(publishDir)))
77 { 131 {
78 if (String.IsNullOrWhiteSpace(publishDir)) 132 var projectReference = facade.ProjectReference;
133 var targetsValue = new MetadataValueList(projectReference, "Targets");
134
135 if (facade.Modified)
79 { 136 {
80 publishDir = CalculatePublishDirFromProjectReference(projectReference, intermediateFolder); 137 var configurationValue = new MetadataValue(projectReference, "Configuration");
138 var platformValue = new MetadataValue(projectReference, "Platform");
139 var fullConfigurationValue = new MetadataValue(projectReference, "FullConfiguration");
140 var additionalProperties = new MetadataValueList(projectReference, "AdditionalProperties");
141 var bindName = new MetadataValue(projectReference, "BindName");
142 var bindPath = new MetadataValue(projectReference, "BindPath");
143
144 var publishDir = facade.CalculatePublishDir();
145
146 additionalProperties.SetValue("PublishDir=", publishDir);
147 additionalProperties.SetValue("RuntimeIdentifier=", facade.RuntimeIdentifier);
148
149 additionalProperties.Apply();
150
151 if (!String.IsNullOrWhiteSpace(facade.Configuration))
152 {
153 projectReference.SetMetadata("SetConfiguration", $"Configuration={facade.Configuration}");
154
155 if (configurationValue.HadValue)
156 {
157 configurationValue.SetValue(facade.Configuration);
158 configurationValue.Apply();
159 }
160 }
161
162 if (!String.IsNullOrWhiteSpace(facade.Platform))
163 {
164 projectReference.SetMetadata("SetPlatform", $"Platform={facade.Platform}");
165
166 if (platformValue.HadValue)
167 {
168 platformValue.SetValue(facade.Platform);
169 platformValue.Apply();
170 }
171 }
172
173 if (fullConfigurationValue.HadValue && (configurationValue.Modified || platformValue.Modified))
174 {
175 fullConfigurationValue.SetValue($"{configurationValue.Value}|{platformValue.Value}");
176 fullConfigurationValue.Apply();
177 }
178
179 if (!String.IsNullOrWhiteSpace(facade.TargetFramework))
180 {
181 projectReference.SetMetadata("SetTargetFramework", $"TargetFramework={facade.TargetFramework}");
182 }
183
184 var bindNameSuffix = facade.CalculateBindNameSuffix();
185 if (!String.IsNullOrWhiteSpace(bindNameSuffix))
186 {
187 var bindNamePrefix = bindName.HadValue ? bindName.Value : Path.GetFileNameWithoutExtension(projectReference.ItemSpec);
188
189 bindName.SetValue(ToolsCommon.CreateIdentifierFromValue(bindNamePrefix + bindNameSuffix));
190 bindName.Apply();
191 }
192
193 if (!bindPath.HadValue)
194 {
195 bindPath.SetValue(publishDir);
196 bindPath.Apply();
197 }
81 } 198 }
82 199
83 publishDir = AppendTargetFrameworkFromProjectReference(projectReference, publishDir); 200 if (facade.Publish)
201 {
202 var publishTargets = new MetadataValueList(projectReference, "PublishTargets");
203
204 if (publishTargets.HadValue)
205 {
206 targetsValue.AddRange(publishTargets.Values);
207 }
208 else
209 {
210 targetsValue.SetValue(null, "Publish");
211 }
212
213 // GetTargetPath target always needs to be last so we can set bind paths to the output location of the project reference.
214 if (targetsValue.Values.Count == 0 || !"GetTargetPath".Equals(targetsValue.Values[targetsValue.Values.Count - 1], StringComparison.OrdinalIgnoreCase))
215 {
216 targetsValue.Values.Remove("GetTargetPath");
217 targetsValue.SetValue(null, "GetTargetPath");
218 }
219 }
84 220
85 publishDir = Path.GetFullPath(publishDir); 221 if (targetsValue.Modified)
222 {
223 targetsValue.Apply();
224 }
86 225
87 this.AddPublishPropertiesToProjectReference(projectReference, publishDir); 226 this.Log.LogMessage(MessageImportance.Low, "Adding metadata to project reference {0} Targets {1}, BindPath {2}={3}, AdditionalProperties: {4}",
227 projectReference.ItemSpec, projectReference.GetMetadata("Targets"), projectReference.GetMetadata("BindName"), projectReference.GetMetadata("BindPath"), projectReference.GetMetadata("AdditionalProperties"));
88 228
89 return true; 229 yield return projectReference;
90 } 230 }
91
92 return false;
93 } 231 }
94 232
95 private bool TrySetTargetFrameworksOnProjectReference(ITaskItem projectReference, List<ITaskItem> additionalProjectReferences) 233 private static IEnumerable<ExpansionTerms> ExpandTerms(IReadOnlyCollection<string> firstTerms, IReadOnlyCollection<string> secondTerms)
96 { 234 {
97 var setTargetFramework = projectReference.GetMetadata("SetTargetFramework"); 235 if (firstTerms.Count == 0)
98 var targetFrameworks = projectReference.GetMetadata("TargetFrameworks"); 236 {
99 var targetFrameworksToSet = targetFrameworks.Split(TargetFrameworksSplitter).Where(s => !String.IsNullOrWhiteSpace(s)).ToList(); 237 firstTerms = new[] { String.Empty };
238 }
100 239
101 if (String.IsNullOrWhiteSpace(setTargetFramework) && targetFrameworksToSet.Count > 0) 240 foreach (var firstTerm in firstTerms)
102 { 241 {
103 // First, clone the project reference so there are enough duplicates for all of the 242 var pairSplit = firstTerm.Split(MetadataPairSplitter, 2);
104 // requested target frameworks. 243
105 for (var i = 1; i < targetFrameworksToSet.Count; ++i) 244 // No pair indicator so expand the first term by the second term.
245 if (pairSplit.Length == 1)
106 { 246 {
107 additionalProjectReferences.Add(new TaskItem(projectReference)); 247 if (secondTerms.Count == 0)
248 {
249 yield return new ExpansionTerms(firstTerm, null);
250 }
251 else
252 {
253 foreach (var secondTerm in secondTerms)
254 {
255 yield return new ExpansionTerms(firstTerm, secondTerm);
256 }
257 }
108 } 258 }
109 259 else // there was a pair like "first|second" or "first|" or "|second" in the first term, so return that value as the pair.
110 // Then set the target framework on each project reference.
111 for (var i = 0; i < targetFrameworksToSet.Count; ++i)
112 { 260 {
113 var reference = (i == 0) ? projectReference : additionalProjectReferences[i - 1]; 261 yield return new ExpansionTerms(pairSplit[0], pairSplit[1]);
114
115 this.SetTargetFrameworkOnProjectReference(reference, targetFrameworksToSet[i]);
116 } 262 }
263 }
264 }
117 265
118 return true; 266 private class ProjectReferenceFacade
267 {
268 private string configuration;
269 private string platform;
270 private string targetFramework;
271 private string runtimeIdentifier;
272
273 public ProjectReferenceFacade(ITaskItem projectReference, IReadOnlyCollection<string> availableConfigurations, string configuration, IReadOnlyCollection<string> availablePlatforms, string platform, IReadOnlyCollection<string> availableTargetFrameworks, string targetFramework, IReadOnlyCollection<string> availableRuntimeIdentifiers, string runtimeIdentifier, string publishBaseDir)
274 {
275 this.ProjectReference = projectReference;
276 this.AvailableConfigurations = availableConfigurations;
277 this.configuration = configuration;
278 this.AvailablePlatforms = availablePlatforms;
279 this.platform = platform;
280 this.AvailableTargetFrameworks = availableTargetFrameworks;
281 this.targetFramework = targetFramework;
282 this.AvailableRuntimeIdentifiers = availableRuntimeIdentifiers;
283 this.runtimeIdentifier = runtimeIdentifier;
284 this.PublishBaseDir = publishBaseDir;
285 this.Modified = !String.IsNullOrWhiteSpace(configuration) || !String.IsNullOrWhiteSpace(platform) ||
286 !String.IsNullOrWhiteSpace(targetFramework) || !String.IsNullOrWhiteSpace(runtimeIdentifier) ||
287 !String.IsNullOrWhiteSpace(publishBaseDir);
119 } 288 }
120 289
121 if (!String.IsNullOrWhiteSpace(setTargetFramework) && !String.IsNullOrWhiteSpace(targetFrameworks)) 290 public ITaskItem ProjectReference { get; }
291
292 public bool Modified { get; private set; }
293
294 public IReadOnlyCollection<string> AvailableConfigurations { get; }
295
296 public IReadOnlyCollection<string> AvailablePlatforms { get; }
297
298 public IReadOnlyCollection<string> AvailableRuntimeIdentifiers { get; }
299
300 public IReadOnlyCollection<string> AvailableTargetFrameworks { get; }
301
302 public bool Publish => !String.IsNullOrEmpty(this.PublishBaseDir);
303
304 public string PublishBaseDir { get; }
305
306 public string Configuration
122 { 307 {
123 this.Log.LogWarning("ProjectReference {0} contains metadata for both SetTargetFramework and TargetFrameworks. SetTargetFramework takes precedent so the TargetFrameworks value '{1}' is ignored", projectReference.ItemSpec, targetFrameworks); 308 get => this.configuration;
309 set => this.configuration = this.SetWithModified(value, this.configuration);
124 } 310 }
125 311
126 return false; 312 public string Platform
127 } 313 {
314 get => this.platform;
315 set => this.platform = this.SetWithModified(value, this.platform);
316 }
128 317
129 private void AddPublishPropertiesToProjectReference(ITaskItem projectReference, string publishDir) 318 public string TargetFramework
130 {
131 var additionalProperties = projectReference.GetMetadata("AdditionalProperties");
132 if (!String.IsNullOrWhiteSpace(additionalProperties))
133 { 319 {
134 additionalProperties += ";"; 320 get => this.targetFramework;
321 set => this.targetFramework = this.SetWithModified(value, this.targetFramework);
135 } 322 }
136 323
137 additionalProperties += "PublishDir=" + publishDir; 324 public string RuntimeIdentifier
325 {
326 get => this.runtimeIdentifier;
327 set => this.runtimeIdentifier = this.SetWithModified(value, this.runtimeIdentifier);
328 }
138 329
139 var bindPath = ToolsCommon.GetMetadataOrDefault(projectReference, "BindPath", publishDir); 330 public ProjectReferenceFacade Clone()
331 {
332 return new ProjectReferenceFacade(new TaskItem(this.ProjectReference), this.AvailableConfigurations, this.configuration, this.AvailablePlatforms, this.platform, this.AvailableTargetFrameworks, this.targetFramework, this.AvailableRuntimeIdentifiers, this.runtimeIdentifier, this.PublishBaseDir);
333 }
140 334
141 var publishTargets = projectReference.GetMetadata("PublishTargets"); 335 public static ProjectReferenceFacade CreateFacade(ITaskItem projectReference, TaskLoggingHelper logger, string intermediateFolder)
142 if (String.IsNullOrWhiteSpace(publishTargets))
143 { 336 {
144 publishTargets = "Publish;GetTargetPath"; 337 var configurationsValue = new MetadataValueList(projectReference, "Configurations");
338 var setConfigurationValue = new MetadataValue(projectReference, "SetConfiguration", "Configuration=");
339 var platformsValue = new MetadataValueList(projectReference, "Platforms");
340 var setPlatformValue = new MetadataValue(projectReference, "SetPlatform", "Platform=");
341 var targetFrameworksValue = new MetadataValueList(projectReference, "TargetFrameworks");
342 var setTargetFrameworkValue = new MetadataValue(projectReference, "SetTargetFramework", "TargetFramework=");
343 var runtimeIdentifiersValue = new MetadataValueList(projectReference, "RuntimeIdentifiers");
344 var publishValue = new MetadataValue(projectReference, "Publish", null);
345 var publishDirValue = new MetadataValue(projectReference, "PublishDir", null);
346
347 var configurations = GetFromListAndValidateSetValue(configurationsValue, setConfigurationValue, logger, projectReference, "Configuration=Release");
348
349 var platforms = GetFromListAndValidateSetValue(platformsValue, setPlatformValue, logger, projectReference, "Platform=x64");
350
351 var targetFrameworks = GetFromListAndValidateSetValue(targetFrameworksValue, setTargetFrameworkValue, logger, projectReference, "TargetFramework=tfm");
352
353 string publishBaseDir = null;
354
355 if (publishValue.Value.Equals("true", StringComparison.OrdinalIgnoreCase) || (!publishValue.HadValue && publishDirValue.HadValue))
356 {
357 if (publishDirValue.HadValue)
358 {
359 publishBaseDir = publishDirValue.Value;
360 }
361 else
362 {
363 publishBaseDir = Path.Combine(intermediateFolder, "publish", Path.GetFileNameWithoutExtension(projectReference.ItemSpec));
364 }
365 }
366
367 return new ProjectReferenceFacade(projectReference, configurations, null, platforms, null, targetFrameworks, null, runtimeIdentifiersValue.Values, null, publishBaseDir);
145 } 368 }
146 else if (!publishTargets.EndsWith(";GetTargetsPath", StringComparison.OrdinalIgnoreCase)) 369
370 public string CalculatePublishDir()
147 { 371 {
148 publishTargets += ";GetTargetsPath"; 372 if (!this.Publish)
373 {
374 return null;
375 }
376
377 var publishDir = this.PublishBaseDir;
378
379 if (!String.IsNullOrWhiteSpace(this.Configuration))
380 {
381 publishDir = Path.Combine(publishDir, this.Configuration);
382 }
383
384 if (!String.IsNullOrWhiteSpace(this.Platform))
385 {
386 publishDir = Path.Combine(publishDir, this.Platform);
387 }
388
389 if (!String.IsNullOrWhiteSpace(this.TargetFramework))
390 {
391 publishDir = Path.Combine(publishDir, this.TargetFramework);
392 }
393
394 if (!String.IsNullOrWhiteSpace(this.RuntimeIdentifier))
395 {
396 publishDir = Path.Combine(publishDir, this.RuntimeIdentifier);
397 }
398
399
400 return Path.GetFullPath(publishDir);
149 } 401 }
150 402
151 projectReference.SetMetadata("AdditionalProperties", additionalProperties); 403 public string CalculateBindNameSuffix()
152 projectReference.SetMetadata("BindPath", bindPath); 404 {
153 projectReference.SetMetadata("Targets", publishTargets); 405 var sb = new StringBuilder();
154 406
155 this.Log.LogMessage(MessageImportance.Low, "Adding publish metadata to project reference {0} Targets {1}, BindPath {2}, AdditionalProperties: {3}", 407 if (!String.IsNullOrWhiteSpace(this.Configuration))
156 projectReference.ItemSpec, projectReference.GetMetadata("Targets"), projectReference.GetMetadata("BindPath"), projectReference.GetMetadata("AdditionalProperties")); 408 {
157 } 409 sb.AppendFormat(".{0}", this.Configuration);
410 }
158 411
159 private void SetTargetFrameworkOnProjectReference(ITaskItem projectReference, string targetFramework) 412 if (!String.IsNullOrWhiteSpace(this.Platform))
160 { 413 {
161 projectReference.SetMetadata("SetTargetFramework", $"TargetFramework={targetFramework}"); 414 sb.AppendFormat(".{0}", this.Platform);
415 }
416
417 if (!String.IsNullOrWhiteSpace(this.TargetFramework))
418 {
419 sb.AppendFormat(".{0}", this.TargetFramework);
420 }
421
422 if (!String.IsNullOrWhiteSpace(this.RuntimeIdentifier))
423 {
424 sb.AppendFormat(".{0}", this.RuntimeIdentifier);
425 }
426
427 return sb.ToString();
428 }
162 429
163 var bindName = projectReference.GetMetadata("BindName"); 430 private string SetWithModified(string newValue, string oldValue)
164 if (String.IsNullOrWhiteSpace(bindName))
165 { 431 {
166 bindName = Path.GetFileNameWithoutExtension(projectReference.ItemSpec); 432 if (String.IsNullOrWhiteSpace(newValue) && String.IsNullOrWhiteSpace(oldValue))
433 {
434 return String.Empty;
435 }
436 else if (oldValue != newValue)
437 {
438 this.Modified = true;
439 return newValue;
440 }
167 441
168 projectReference.SetMetadata("BindName", $"{bindName}.{targetFramework}"); 442 return oldValue;
169 } 443 }
170 444
171 this.Log.LogMessage(MessageImportance.Low, "Adding target framework metadata to project reference {0} SetTargetFramework: {1}, BindName: {2}", 445 private static List<string> GetFromListAndValidateSetValue(MetadataValueList listValue, MetadataValue setValue, TaskLoggingHelper logger, ITaskItem projectReference, string setExample)
172 projectReference.ItemSpec, projectReference.GetMetadata("SetTargetFramework"), projectReference.GetMetadata("BindName")); 446 {
173 } 447 var targetFrameworks = listValue.Values;
174 448
175 private static string CalculatePublishDirFromProjectReference(ITaskItem projectReference, string intermediateFolder) 449 if (setValue.HadValue)
176 { 450 {
177 var publishDir = Path.Combine("publish", Path.GetFileNameWithoutExtension(projectReference.ItemSpec)); 451 if (listValue.HadValue)
452 {
453 logger.LogMessage("ProjectReference {0} contains metadata for both {1} and {2}. {2} takes precedent so the {1} value '{3}' will be ignored", projectReference.ItemSpec, setValue.Name, listValue.Name, setValue.OriginalValue);
454 }
455 else if (!setValue.ValidValue)
456 {
457 logger.LogError("ProjectReference {0} contains invalid {1} value '{2}'. The {1} value should look something like '{3}'.", projectReference.ItemSpec, setValue.Name, setValue.OriginalValue, setExample);
458 }
459 }
178 460
179 return Path.Combine(intermediateFolder, publishDir); 461 return targetFrameworks;
462 }
180 } 463 }
181 464
182 private static string AppendTargetFrameworkFromProjectReference(ITaskItem projectReference, string publishDir) 465 private class ExpansionTerms
183 { 466 {
184 var setTargetFramework = projectReference.GetMetadata("SetTargetFramework"); 467 public ExpansionTerms(string firstTerm, string secondTerm)
185
186 if (setTargetFramework.StartsWith("TargetFramework=") && setTargetFramework.Length > "TargetFramework=".Length)
187 { 468 {
188 var targetFramework = setTargetFramework.Substring("TargetFramework=".Length); 469 this.FirstTerm = firstTerm;
189 470 this.SecondTerm = secondTerm;
190 publishDir = Path.Combine(publishDir, targetFramework);
191 } 471 }
192 472
193 return publishDir; 473 public string FirstTerm { get; }
474
475 public string SecondTerm { get; }
194 } 476 }
195 } 477 }
196} 478}