~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
                string lastBuildRuntime;
57
57
                string lastFileName;
58
58
                ITimeTracker timer;
59
 
                bool useXBuild;
60
 
                MSBuildVerbosity verbosity;
 
59
                bool forceUseMSBuild;
61
60
 
62
61
                struct ItemInfo {
63
62
                        public MSBuildItem Item;
87
86
                                return subtypeGuids;
88
87
                        }
89
88
                }
90
 
                
 
89
 
91
90
                public MSBuildProjectHandler ()
92
91
                {
93
92
                }
104
103
                                this.targetImports.AddRange (import.Split (':'));
105
104
                        
106
105
                        Runtime.SystemAssemblyService.DefaultRuntimeChanged += OnDefaultRuntimeChanged;
107
 
                        
108
 
                        //FIXME: Update these when the properties change
109
 
                        useXBuild = PropertyService.Get ("MonoDevelop.Ide.BuildWithMSBuild", false);
110
 
                        verbosity = PropertyService.Get ("MonoDevelop.Ide.MSBuildVerbosity", MSBuildVerbosity.Normal);
111
106
                }
112
107
                
113
108
                void OnDefaultRuntimeChanged (object o, EventArgs args)
145
140
                        }
146
141
                        return projectBuilder;
147
142
                }
148
 
                
 
143
 
 
144
                void CleanupProjectBuilder ()
 
145
                {
 
146
                        if (projectBuilder != null) {
 
147
                                projectBuilder.Dispose ();
 
148
                                projectBuilder = null;
 
149
                        }
 
150
                }
 
151
 
149
152
                public override void Dispose ()
150
153
                {
151
154
                        base.Dispose ();
152
 
                        if (projectBuilder != null) {
153
 
                                projectBuilder.Dispose ();
154
 
                                projectBuilder = null;
155
 
                        }
 
155
                        CleanupProjectBuilder ();
156
156
                        Runtime.SystemAssemblyService.DefaultRuntimeChanged -= OnDefaultRuntimeChanged;
157
157
                }
158
158
                
165
165
                        }
166
166
                        return configObject.Platform;
167
167
                }
 
168
 
 
169
                ProjectConfigurationInfo[] GetConfigurations (SolutionEntityItem item, ConfigurationSelector configuration)
 
170
                {
 
171
                        // Returns a list of project/configuration information for the provided item and all its references
 
172
                        List<ProjectConfigurationInfo> configs = new List<ProjectConfigurationInfo> ();
 
173
                        var c = item.GetConfiguration (configuration);
 
174
                        configs.Add (new ProjectConfigurationInfo () {
 
175
                                ProjectFile = item.FileName,
 
176
                                Configuration = c.Name,
 
177
                                Platform = GetExplicitPlatform (c)
 
178
                        });
 
179
                        foreach (var refProject in item.GetReferencedItems (configuration).OfType<Project> ()) {
 
180
                                var refConfig = refProject.GetConfiguration (configuration);
 
181
                                configs.Add (new ProjectConfigurationInfo () {
 
182
                                        ProjectFile = refProject.FileName,
 
183
                                        Configuration = refConfig.Name,
 
184
                                        Platform = GetExplicitPlatform (refConfig)
 
185
                                });
 
186
                        }
 
187
                        return configs.ToArray ();
 
188
                }
168
189
                
169
190
                IEnumerable<string> IAssemblyReferenceHandler.GetAssemblyReferences (ConfigurationSelector configuration)
170
191
                {
171
 
                        if (useXBuild) {
 
192
                        if (UseMSBuildEngine) {
172
193
                                // Get the references list from the msbuild project
173
194
                                SolutionEntityItem item = (SolutionEntityItem) Item;
174
195
                                RemoteProjectBuilder builder = GetProjectBuilder ();
175
 
                                SolutionItemConfiguration configObject = item.GetConfiguration (configuration);
176
 
                                foreach (string s in builder.GetAssemblyReferences (configObject.Name, GetExplicitPlatform (configObject)))
 
196
                                var configs = GetConfigurations (item, configuration);
 
197
                                foreach (string s in builder.GetAssemblyReferences (configs))
177
198
                                        yield return s;
178
199
                        }
179
200
                        else {
 
201
                                CleanupProjectBuilder ();
180
202
                                DotNetProject item = Item as DotNetProject;
181
203
                                if (item == null)
182
204
                                        yield break;
189
211
                
190
212
                public override BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
191
213
                {
192
 
                        if (useXBuild) {
 
214
                        if (UseMSBuildEngine) {
193
215
                                SolutionEntityItem item = Item as SolutionEntityItem;
194
216
                                if (item != null) {
195
217
                                        
196
 
                                        SolutionItemConfiguration configObject = item.GetConfiguration (configuration);
197
 
                                
198
218
                                        LogWriter logWriter = new LogWriter (monitor.Log);
199
219
                                        RemoteProjectBuilder builder = GetProjectBuilder ();
200
 
                                        MSBuildResult[] results = builder.RunTarget (target, configObject.Name, GetExplicitPlatform (configObject),
201
 
                                                logWriter, verbosity);
 
220
                                        var configs = GetConfigurations (item, configuration);
 
221
                                        MSBuildResult[] results = builder.RunTarget (target, configs, logWriter, MSBuildProjectService.DefaultMSBuildVerbosity);
202
222
                                        System.Runtime.Remoting.RemotingServices.Disconnect (logWriter);
203
223
                                        
204
224
                                        BuildResult br = new BuildResult ();
212
232
                                }
213
233
                        }
214
234
                        else {
 
235
                                CleanupProjectBuilder ();
215
236
                                if (Item is DotNetProject) {
216
237
                                        MD1DotNetProjectHandler handler = new MD1DotNetProjectHandler ((DotNetProject)Item);
217
238
                                        return handler.RunTarget (monitor, target, configuration);
274
295
                                globalGroup = p.AddNewPropertyGroup (false);
275
296
                        
276
297
                        string itemGuid = globalGroup.GetPropertyValue ("ProjectGuid");
 
298
                        if (itemGuid == null)
 
299
                                throw new UserException ("Project file doesn't have a valid ProjectGuid");
 
300
 
 
301
                        itemGuid = itemGuid.ToUpper ();
277
302
                        string projectTypeGuids = globalGroup.GetPropertyValue ("ProjectTypeGuids");
278
303
                        string itemType = globalGroup.GetPropertyValue ("ItemType");
279
304
 
285
310
                                                subtypeGuids.Add (guid);
286
311
                                }
287
312
                        }
 
313
                        // Enable xbuild by default only for standard .NET projects - not for subtypes
 
314
                        //ForceUseMSBuild = subtypeGuids.Count == 0;
288
315
                        
289
316
                        try {
290
317
                                timer.Trace ("Create item instance");
309
336
                                timer.End ();
310
337
                        }
311
338
                }
 
339
 
 
340
                internal bool UseMSBuildEngine {
 
341
                        get { return forceUseMSBuild || MSBuildProjectService.DefaultBuildWithMSBuild; }
 
342
                }
312
343
                
313
 
                internal bool UseXbuild {
314
 
                        get { return useXBuild; }
315
 
                        set { useXBuild = value; }
 
344
                internal bool ForceUseMSBuild {
 
345
                        get { return forceUseMSBuild; }
 
346
                        set { forceUseMSBuild = value; }
316
347
                }
317
348
                
318
349
                // All of the last 4 parameters are optional, but at least one must be provided.
324
355
                        if (!string.IsNullOrEmpty (typeGuids)) {
325
356
                                DotNetProjectSubtypeNode st = MSBuildProjectService.GetDotNetProjectSubtype (typeGuids);
326
357
                                if (st != null) {
327
 
                                        item = st.CreateInstance (language);
328
 
                                        useXBuild = useXBuild || st.UseXBuild;
329
 
                                        if (st.IsMigration) {
330
 
                                                MigrateProject (monitor, st, p, fileName, language);
331
 
                                                
 
358
                                        forceUseMSBuild = st.UseXBuild;
 
359
                                        Type migratedType = null;
 
360
 
 
361
                                        if (st.IsMigration && (migratedType = MigrateProject (monitor, st, p, fileName, language)) != null) {
332
362
                                                var oldSt = st;
333
 
                                                st = MSBuildProjectService.GetItemSubtypeNodes ()
334
 
                                                        .Where (t => t.CanHandleItem ((SolutionEntityItem)item)).Last ();
 
363
                                                st = MSBuildProjectService.GetItemSubtypeNodes ().Last (t => t.CanHandleType (migratedType));
 
364
 
335
365
                                                for (int i = 0; i < subtypeGuids.Count; i++) {
336
366
                                                        if (string.Equals (subtypeGuids[i], oldSt.Guid, StringComparison.OrdinalIgnoreCase)) {
337
367
                                                                subtypeGuids[i] = st.Guid;
339
369
                                                                break;
340
370
                                                        }
341
371
                                                }
 
372
 
342
373
                                                if (oldSt != null)
343
374
                                                        throw new Exception ("Unable to correct flavor GUID");
 
375
 
344
376
                                                var gg = string.Join (";", subtypeGuids) + ";" + TypeGuid;
345
 
                                                p.GetGlobalPropertyGroup ().SetPropertyValue ("ProjectTypeGuids", gg.ToUpper ());
 
377
                                                p.GetGlobalPropertyGroup ().SetPropertyValue ("ProjectTypeGuids", gg.ToUpper (), true);
346
378
                                                p.Save (fileName);
347
379
                                        }
 
380
 
 
381
                                        item = st.CreateInstance (language);
348
382
                                        st.UpdateImports ((SolutionEntityItem)item, targetImports);
349
383
                                } else
350
384
                                        throw new UnknownSolutionItemTypeException (typeGuids);
351
385
                        }
 
386
 
352
387
                        if (item == null && itemClass != null)
353
388
                                item = (SolutionItem) Activator.CreateInstance (itemClass);
354
389
                        
365
400
                                        
366
401
                                item = (SolutionItem) Activator.CreateInstance (dt.ValueType);
367
402
                        }
 
403
 
368
404
                        return item;
369
405
                }
370
406
 
371
 
                void MigrateProject (IProgressMonitor monitor, DotNetProjectSubtypeNode st, MSBuildProject p, string fileName, string language)
 
407
                Type MigrateProject (IProgressMonitor monitor, DotNetProjectSubtypeNode st, MSBuildProject p, string fileName, string language)
372
408
                {
373
409
                        var projectLoadMonitor = monitor as IProjectLoadProgressMonitor;
374
410
                        if (projectLoadMonitor == null) {
 
411
                                // projectLoadMonitor will be null when running through md-tool, but
 
412
                                // this is not fatal if migration is not required, so just ignore it. --abock
 
413
                                if (!st.IsMigrationRequired)
 
414
                                        return null;
 
415
 
375
416
                                LoggingService.LogError (Environment.StackTrace);
376
417
                                monitor.ReportError ("Could not open unmigrated project and no migrator was supplied", null);
377
418
                                throw new Exception ("Could not open unmigrated project and no migrator was supplied");
378
419
                        }
379
420
                        
380
 
                        var migrationType = projectLoadMonitor.ShouldMigrateProject ();
 
421
                        var migrationType = st.MigrationHandler.CanPromptForMigration
 
422
                                ? st.MigrationHandler.PromptForMigration (projectLoadMonitor, p, fileName, language)
 
423
                                : projectLoadMonitor.ShouldMigrateProject ();
381
424
                        if (migrationType == MigrationType.Ignore) {
382
 
                                monitor.ReportError (string.Format ("MonoDevelop cannot open the project '{0}' unless it is migrated.", Path.GetFileName (fileName)), null);
383
 
                                throw new Exception ("The user choose not to migrate the project");
 
425
                                if (st.IsMigrationRequired) {
 
426
                                        monitor.ReportError (string.Format ("{1} cannot open the project '{0}' unless it is migrated.", Path.GetFileName (fileName), BrandingService.ApplicationName), null);
 
427
                                        throw new Exception ("The user choose not to migrate the project");
 
428
                                } else
 
429
                                        return null;
384
430
                        }
385
431
                        
386
432
                        var baseDir = (FilePath) Path.GetDirectoryName (fileName);
399
445
                                        File.Copy (file, Path.Combine (backupDir, Path.GetFileName (file)));
400
446
                        }
401
447
                        
402
 
                        if (!st.MigrationHandler.Migrate (projectLoadMonitor, p, fileName, language))
 
448
                        var type = st.MigrationHandler.Migrate (projectLoadMonitor, p, fileName, language);
 
449
                        if (type == null)
403
450
                                throw new Exception ("Could not migrate the project");
 
451
 
 
452
                        return type;
404
453
                }
405
454
                
406
455
                FileFormat GetFileFormat ()
495
544
                        
496
545
                        foreach (MSBuildItem buildItem in msproject.GetAllItems ()) {
497
546
                                ProjectItem it = ReadItem (ser, buildItem);
498
 
                                if (it != null) {
499
 
                                        EntityItem.Items.Add (it);
 
547
 
 
548
                                if (it == null) continue;
 
549
 
 
550
                                if (it is ProjectFile) {
 
551
                                        ProjectFile file = (ProjectFile)it;
 
552
 
 
553
                                        if (file.IsWildcard)  {
 
554
                                                foreach (ProjectFile wildcardItem in file.ResolveWildcardItems ()) {
 
555
                                                        EntityItem.Items.Add (wildcardItem);
 
556
                                                        
 
557
                                                        // Thanks to IsOriginatedFromWildcard, this item will not be saved back to disk.
 
558
                                                        System.Diagnostics.Debug.Assert (wildcardItem.IsOriginatedFromWildcard);
 
559
                                                }
 
560
 
 
561
                                                // Add to wildcard items (so it can be re-saved) instead of Items (where tools will 
 
562
                                                // try to compile and display these nonstandard items
 
563
                                                EntityItem.WildcardItems.Add (it);
 
564
                                                continue;
 
565
                                        }
500
566
                                }
 
567
 
 
568
                                EntityItem.Items.Add (it);
501
569
                        }
502
570
                        
503
571
                        timer.Trace ("Read configurations");
640
708
                        ClassDataType dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (ob.GetType ());
641
709
                        foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, ob)) {
642
710
                                MSBuildProperty bp = pgroup.GetProperty (prop.Name);
643
 
                                if (bp != null)
644
 
                                        res.SetPropertyValue (bp.Name, bp.Value);
 
711
                                if (bp != null) {
 
712
                                        var preserveCase = prop.DataType is MSBuildBoolDataType;
 
713
                                        res.SetPropertyValue (bp.Name, bp.Value, preserveCase);
 
714
                                }
645
715
                        }
646
716
                        if (ob is DotNetProjectConfiguration) {
647
717
                                object cparams = ((DotNetProjectConfiguration)ob).CompilationParameters;
648
718
                                dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (cparams.GetType ());
649
719
                                foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, cparams)) {
650
720
                                        MSBuildProperty bp = pgroup.GetProperty (prop.Name);
651
 
                                        if (bp != null)
652
 
                                                res.SetPropertyValue (bp.Name, bp.Value);
 
721
                                        if (bp != null) {
 
722
                                                var preserveCase = prop.DataType is MSBuildBoolDataType;
 
723
                                                res.SetPropertyValue (bp.Name, bp.Value, preserveCase);
 
724
                                        }
653
725
                                }
654
726
                        }
655
727
                        return res;
656
728
                }
657
729
                
658
 
                IEnumerable<string> GetMergeToProjectProperties (MSBuildSerializer ser, object ob)
 
730
                IEnumerable<MergedProperty> GetMergeToProjectProperties (MSBuildSerializer ser, object ob)
659
731
                {
660
732
                        ClassDataType dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (ob.GetType ());
661
733
                        foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, ob)) {
662
 
                                if (IsMergeToProjectProperty (prop))
663
 
                                        yield return prop.Name;
 
734
                                if (IsMergeToProjectProperty (prop)) {
 
735
                                        yield return new MergedProperty (prop.Name, prop.DataType is MSBuildBoolDataType);
 
736
                                }
 
737
                        }
 
738
                }
 
739
 
 
740
                struct MergedProperty
 
741
                {
 
742
                        public readonly string Name;
 
743
                        public readonly bool PreserveExistingCase;
 
744
 
 
745
                        public MergedProperty (string name, bool preserveExistingCase)
 
746
                        {
 
747
                                this.Name = name;
 
748
                                this.PreserveExistingCase = preserveExistingCase;
664
749
                        }
665
750
                }
666
751
 
852
937
                        if (eitem.Configurations.Count > 0) {
853
938
                                ItemConfiguration conf = eitem.Configurations.FirstOrDefault<ItemConfiguration> (c => c.Name == "Debug");
854
939
                                if (conf == null) conf = eitem.Configurations [0];
855
 
                                MSBuildProperty bprop = SetGroupProperty (globalGroup, "Configuration", conf.Name, false);
 
940
                                MSBuildProperty bprop = globalGroup.SetPropertyValue ("Configuration", conf.Name, false);
856
941
                                bprop.Condition = " '$(Configuration)' == '' ";
857
942
                                
858
943
                                string platform = conf.Platform.Length == 0 ? "AnyCPU" : conf.Platform;
859
 
                                bprop = SetGroupProperty (globalGroup, "Platform", platform, false);
 
944
                                bprop = globalGroup.SetPropertyValue ("Platform", platform, false);
860
945
                                bprop.Condition = " '$(Platform)' == '' ";
861
946
                        }
862
947
                        
863
948
                        if (TypeGuid == MSBuildProjectService.GenericItemGuid) {
864
949
                                DataType dt = MSBuildProjectService.DataContext.GetConfigurationDataType (Item.GetType ());
865
 
                                SetGroupProperty (globalGroup, "ItemType", dt.Name, false);
 
950
                                globalGroup.SetPropertyValue ("ItemType", dt.Name, false);
866
951
                        }
867
952
 
868
953
                        Item.ExtendedProperties ["ProjectGuid"] = Item.ItemId;
918
1003
                        // Convert debug property
919
1004
                        
920
1005
                        foreach (SolutionItemConfiguration conf in eitem.Configurations) {
921
 
                                DotNetProjectConfiguration cp = conf as MonoDevelop.Projects.DotNetProjectConfiguration;
922
 
                                if (cp != null) {
923
 
                                        if (newProject)
924
 
                                                cp.ExtendedProperties ["ErrorReport"] = "prompt";
925
 
                                        
926
 
                                        string debugType = (string) cp.ExtendedProperties ["DebugType"];
927
 
                                        if (cp.DebugMode) {
928
 
                                                if (debugType != "full" && debugType != "pdbonly")
929
 
                                                        cp.ExtendedProperties ["DebugType"] = "full";
930
 
                                        }
931
 
                                        else if (debugType != "none" && debugType != "pdbonly")
932
 
                                                cp.ExtendedProperties ["DebugType"] = "none";
 
1006
                                if (newProject && conf is DotNetProjectConfiguration) {
 
1007
                                        conf.ExtendedProperties ["ErrorReport"] = "prompt";
933
1008
                                }
934
1009
                        }
935
1010
                        
937
1012
 
938
1013
                        if (eitem.Configurations.Count > 0) {
939
1014
                                List<ConfigData> configData = GetConfigData (msproject, true);
940
 
                                
941
 
                                Dictionary<string,string> mergeToProjectProperties = new Dictionary<string,string> ();
942
 
                                HashSet<string> mergeToProjectPropertyNames = new HashSet<string> (GetMergeToProjectProperties ( ser, eitem.Configurations [0]));
943
 
                                HashSet<string> mergeToProjectPropertyNamesCopy = new HashSet<string> (mergeToProjectPropertyNames);
 
1015
 
 
1016
                                var mergeToProjectPropertyValues = new Dictionary<string,MergedPropertyValue> ();
 
1017
                                var mergeToProjectProperties = new HashSet<MergedProperty> (GetMergeToProjectProperties (ser, eitem.Configurations [0]));
 
1018
                                var mergeToProjectPropertyNames = new HashSet<string> (mergeToProjectProperties.Select (p => p.Name));
944
1019
                                
945
1020
                                foreach (SolutionItemConfiguration conf in eitem.Configurations) {
946
1021
                                        bool newConf = false;
988
1063
                                        
989
1064
                                        WritePropertyGroupMetadata (propGroup, ditem.ItemData, ser, conf, netConfig != null ? netConfig.CompilationParameters : null);
990
1065
                                        
991
 
                                        CollectMergetoprojectProperties (propGroup, mergeToProjectPropertyNames, mergeToProjectProperties);
 
1066
                                        CollectMergetoprojectProperties (propGroup, mergeToProjectProperties, mergeToProjectPropertyValues);
992
1067
                                        
993
1068
                                        if (baseGroup != null)
994
 
                                                propGroup.UnMerge (baseGroup, mergeToProjectPropertyNamesCopy);
 
1069
                                                propGroup.UnMerge (baseGroup, mergeToProjectPropertyNames);
995
1070
                                }
996
1071
                                
997
1072
                                // Move properties with common values from configurations to the main
998
1073
                                // property group
999
 
                                foreach (KeyValuePair<string,string> prop in mergeToProjectProperties)
1000
 
                                        globalGroup.SetPropertyValue (prop.Key, prop.Value);
1001
 
                                foreach (string prop in mergeToProjectPropertyNamesCopy) {
1002
 
                                        if (!mergeToProjectProperties.ContainsKey (prop))
 
1074
                                foreach (KeyValuePair<string,MergedPropertyValue> prop in mergeToProjectPropertyValues)
 
1075
                                        globalGroup.SetPropertyValue (prop.Key, prop.Value.Value, prop.Value.PreserveExistingCase);
 
1076
                                foreach (string prop in mergeToProjectPropertyNames) {
 
1077
                                        if (!mergeToProjectPropertyValues.ContainsKey (prop))
1003
1078
                                                globalGroup.RemoveProperty (prop);
1004
1079
                                }
1005
1080
                                foreach (SolutionItemConfiguration conf in eitem.Configurations) {
1006
1081
                                        MSBuildPropertyGroup propGroup = FindPropertyGroup (configData, conf).Group;
1007
 
                                        foreach (string mp in mergeToProjectProperties.Keys)
 
1082
                                        foreach (string mp in mergeToProjectPropertyValues.Keys)
1008
1083
                                                propGroup.RemoveProperty (mp);
1009
1084
                                }
1010
1085
                                
1022
1097
                                oldItems [item.Name + "<" + item.Include] = new ItemInfo () { Item=item };
1023
1098
                        
1024
1099
                        // Add the new items
1025
 
                        foreach (object ob in ((SolutionEntityItem)Item).Items)
 
1100
                        foreach (object ob in ((SolutionEntityItem)Item).Items.Concat (((SolutionEntityItem)Item).WildcardItems))
1026
1101
                                SaveItem (monitor, ser, msproject, ob, oldItems);
1027
 
                        
 
1102
 
1028
1103
                        foreach (ItemInfo itemInfo in oldItems.Values) {
1029
1104
                                if (!itemInfo.Added)
1030
1105
                                        msproject.RemoveItem (itemInfo.Item);
1034
1109
                                var moniker = dotNetProject.TargetFramework.Id;
1035
1110
                                bool supportsMultipleFrameworks = TargetFormat.FrameworkVersions.Length > 0;
1036
1111
                                var def = dotNetProject.GetDefaultTargetFrameworkForFormat (GetFileFormat ());
1037
 
                                bool isDefaultIdentifier = def.Identifier == moniker.Identifier;
1038
 
                                bool isDefaultVersion = isDefaultIdentifier && def.Version == moniker.Version;
1039
 
                                bool isDefaultProfile = isDefaultVersion && def.Profile == moniker.Profile;
1040
1112
 
1041
 
                                // If the format only supports one fx version, or the version is the default, there is no need to store it
1042
 
                                if (!isDefaultVersion && supportsMultipleFrameworks)
1043
 
                                        SetGroupProperty (globalGroup, "TargetFrameworkVersion", "v" + moniker.Version, false);
1044
 
                                else
1045
 
                                        globalGroup.RemoveProperty ("TargetFrameworkVersion");
 
1113
                                // If the format only supports one fx version, or the version is the default, there is no need to store it.
 
1114
                                // However, is there is already a value set, do not remove it.
 
1115
                                if (supportsMultipleFrameworks) {
 
1116
                                        SetIfPresentOrNotDefaultValue (globalGroup, "TargetFrameworkVersion", "v" + moniker.Version, "v" + def.Version);
 
1117
                                }
1046
1118
                                
1047
1119
                                if (TargetFormat.SupportsMonikers) {
1048
 
                                        if (!isDefaultIdentifier && def.Identifier != moniker.Identifier)
1049
 
                                                SetGroupProperty (globalGroup, "TargetFrameworkIdentifier", moniker.Identifier, false);
1050
 
                                        else
1051
 
                                                globalGroup.RemoveProperty ("TargetFrameworkIdentifier");
1052
 
                                        
1053
 
                                        if (!isDefaultProfile && def.Profile != moniker.Profile)
1054
 
                                                SetGroupProperty (globalGroup, "TargetFrameworkProfile", moniker.Profile, false);
1055
 
                                        else
1056
 
                                                globalGroup.RemoveProperty ("TargetFrameworkProfile");
 
1120
                                        SetIfPresentOrNotDefaultValue (globalGroup, "TargetFrameworkIdentifier", moniker.Identifier, def.Identifier);
 
1121
                                        SetIfPresentOrNotDefaultValue (globalGroup, "TargetFrameworkProfile", moniker.Profile, def.Profile);
1057
1122
                                }
1058
1123
                        }
1059
1124
 
1091
1156
                        if (projectBuilder != null)
1092
1157
                                projectBuilder.Refresh ();
1093
1158
                }
 
1159
 
 
1160
                void SetIfPresentOrNotDefaultValue (MSBuildPropertySet propGroup, string name, string value, string defaultValue)
 
1161
                {
 
1162
                        bool hasDefaultValue = string.IsNullOrEmpty (value) || value == defaultValue;
 
1163
                        var prop = propGroup.GetProperty (name);
 
1164
                        if (prop != null) {
 
1165
                                //if the value is default or empty, only remove the element if it was not already the default or empty
 
1166
                                //to avoid unnecessary project file churn
 
1167
                                if (hasDefaultValue) {
 
1168
                                        var existing = prop.Value;
 
1169
                                        bool alreadyHadDefaultValue = string.IsNullOrEmpty (existing) || existing == defaultValue;
 
1170
                                        if (!alreadyHadDefaultValue)
 
1171
                                                propGroup.RemoveProperty (name);
 
1172
                                } else {
 
1173
                                        prop.Value = value;
 
1174
                                }
 
1175
                        } else if (!hasDefaultValue) {
 
1176
                                propGroup.SetPropertyValue (name, value, false);
 
1177
                        }
 
1178
                }
1094
1179
                
1095
1180
                void ForceDefaultValueSerialization (MSBuildSerializer ser, MSBuildPropertySet baseGroup, object ob)
1096
1181
                {
1101
1186
                        }
1102
1187
                }
1103
1188
 
1104
 
                void CollectMergetoprojectProperties (MSBuildPropertyGroup pgroup, HashSet<string> propertyNames, Dictionary<string,string> mergeToProjectProperties)
 
1189
                void CollectMergetoprojectProperties (MSBuildPropertyGroup pgroup, HashSet<MergedProperty> properties, Dictionary<string,MergedPropertyValue> mergeToProjectProperties)
1105
1190
                {
1106
1191
                        // This method checks every property in pgroup which has the MergeToProject flag.
1107
1192
                        // If the value of this property is the same as the one stored in mergeToProjectProperties
1108
1193
                        // it means that the property can be merged to the main project property group (so far).
1109
1194
                        
1110
 
                        foreach (string pname in new List<String> (propertyNames)) {
1111
 
                                MSBuildProperty prop = pgroup.GetProperty (pname);
 
1195
                        foreach (var pinfo in new List<MergedProperty> (properties)) {
 
1196
                                MSBuildProperty prop = pgroup.GetProperty (pinfo.Name);
1112
1197
                                
1113
 
                                string mvalue;
1114
 
                                if (!mergeToProjectProperties.TryGetValue (pname, out mvalue)) {
 
1198
                                MergedPropertyValue mvalue;
 
1199
                                if (!mergeToProjectProperties.TryGetValue (pinfo.Name, out mvalue)) {
1115
1200
                                        if (prop != null) {
1116
1201
                                                // This is the first time the value is checked. Just assign it.
1117
 
                                                mergeToProjectProperties.Add (pname, prop.Value);
 
1202
                                                mergeToProjectProperties.Add (pinfo.Name, new MergedPropertyValue (prop.Value, pinfo.PreserveExistingCase));
1118
1203
                                                continue;
1119
1204
                                        }
1120
1205
                                        // If there is no value, it can't be merged
1121
1206
                                }
1122
 
                                else if (prop != null && prop.Value.Equals (mvalue, StringComparison.CurrentCultureIgnoreCase))
 
1207
                                else if (prop != null && string.Equals (prop.Value, mvalue.Value, StringComparison.OrdinalIgnoreCase))
1123
1208
                                        // Same value. It can be merged.
1124
1209
                                        continue;
1125
1210
 
1126
1211
                                // The property can't be merged because different configurations have different
1127
1212
                                // values for it. Remove it from the list.
1128
 
                                propertyNames.Remove (pname);
1129
 
                                mergeToProjectProperties.Remove (pname);
1130
 
                        }
1131
 
                }
1132
 
 
 
1213
                                properties.Remove (pinfo);
 
1214
                                mergeToProjectProperties.Remove (pinfo.Name);
 
1215
                        }
 
1216
                }
 
1217
 
 
1218
                struct MergedPropertyValue
 
1219
                {
 
1220
                        public readonly string Value;
 
1221
                        public readonly bool PreserveExistingCase;
 
1222
 
 
1223
                        public MergedPropertyValue (string value, bool preserveExistingCase)
 
1224
                        {
 
1225
                                this.Value = value;
 
1226
                                this.PreserveExistingCase = preserveExistingCase;
 
1227
                        }
 
1228
                }
1133
1229
                
1134
1230
                void SaveItem (MonoDevelop.Core.IProgressMonitor monitor, MSBuildSerializer ser, MSBuildProject msproject, object ob, Dictionary<string,ItemInfo> oldItems)
1135
1231
                {
1154
1250
                
1155
1251
                void SaveProjectFile (MSBuildSerializer ser, MSBuildProject msproject, ProjectFile file, Dictionary<string,ItemInfo> oldItems)
1156
1252
                {
 
1253
                        if (file.IsOriginatedFromWildcard) return;
 
1254
 
1157
1255
                        string itemName = (file.Subtype == Subtype.Directory)? "Folder" : file.BuildAction;
1158
1256
 
1159
1257
                        string path = MSBuildProjectService.ToMSBuildPath (Item.ItemDirectory, file.FilePath);
1430
1528
                        foreach (DataNode node in itemData) {
1431
1529
                                notWrittenProps.Remove (node.Name);
1432
1530
                                ConvertToMsbuildFormat (node);
1433
 
                                SetGroupProperty (propGroup, node.Name, GetXmlString (node), node is DataItem);
 
1531
 
 
1532
                                // In the other msbuild contexts (metadata, solution properties, etc) we TitleCase by default, so the node.Value is TitleCase.
 
1533
                                // However, for property value, we lowercase by default and preserve existing case to reduce noise on VS-created files.
 
1534
                                var boolNode = node as MSBuildBoolDataValue;
 
1535
                                string value;
 
1536
                                bool preserveExistingCase;
 
1537
                                if (boolNode != null) {
 
1538
                                        value = boolNode.RawValue? "true" : "false";
 
1539
                                        preserveExistingCase = true;
 
1540
                                } else {
 
1541
                                        value = GetXmlString (node);
 
1542
                                        preserveExistingCase = false;
 
1543
                                }
 
1544
 
 
1545
                                propGroup.SetPropertyValue (node.Name, value, preserveExistingCase);
1434
1546
                        }
1435
1547
                        foreach (string prop in notWrittenProps)
1436
1548
                                propGroup.RemoveProperty (prop);
1473
1585
                        return configData;
1474
1586
                }
1475
1587
                
1476
 
                MSBuildProperty SetGroupProperty (MSBuildPropertySet propGroup, string name, string value, bool isLiteral)
1477
 
                {
1478
 
                        propGroup.SetPropertyValue (name, value);
1479
 
                        return propGroup.GetProperty (name);
1480
 
                }
1481
 
                
1482
1588
                ConfigData FindPropertyGroup (List<ConfigData> configData, SolutionItemConfiguration config)
1483
1589
                {
1484
1590
                        foreach (ConfigData data in configData) {
1646
1752
                        new ItemMember (typeof(SolutionEntityItem), "SchemaVersion"),
1647
1753
                        new ItemMember (typeof(SolutionEntityItem), "ProjectGuid"),
1648
1754
                        new ItemMember (typeof(SolutionEntityItem), "ProjectTypeGuids"),
1649
 
                        new ItemMember (typeof(DotNetProjectConfiguration), "DebugType"),
1650
1755
                        new ItemMember (typeof(DotNetProjectConfiguration), "ErrorReport"),
1651
1756
                        new ItemMember (typeof(DotNetProjectConfiguration), "TargetFrameworkVersion", new object[] { new MergeToProjectAttribute () }),
1652
1757
                        new ItemMember (typeof(ProjectReference), "RequiredTargetFramework"),
1772
1877
                        if (instance is ProjectFile)
1773
1878
                                return prop.IsExtendedProperty (typeof(ProjectFile));
1774
1879
                        if (instance is ProjectReference)
1775
 
                                return prop.IsExtendedProperty (typeof(ProjectReference)) || prop.Name == "Package";
 
1880
                                return prop.IsExtendedProperty (typeof(ProjectReference)) || prop.Name == "Package" || prop.Name == "Aliases";
1776
1881
                        if (instance is DotNetProjectConfiguration)
1777
1882
                                if (prop.Name == "CodeGeneration")
1778
1883
                                        return false;