aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiguel Costa <miguel.costa@qt.io>2019-09-19 15:22:30 +0200
committerMiguel Costa <miguel.costa@qt.io>2019-09-30 10:27:09 +0000
commit99c64ac9834500eff969a77fddc2a81722964226 (patch)
tree52bef1ab20b6a0612e8fb808b7dc5e47b98b5768
parentfdbec35c590f524f6f9ce8f2e6a7328f2f3df508 (diff)
Add conversion to project format v3.1
Project format conversion to version 3.1 from versions 2.0 and 3.0. Task-number: QTVSADDINBUG-651 Change-Id: Ia4b9acc1f422a0c90f3f835aefa9c8a1d2ffc19e Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
-rw-r--r--src/qtprojectlib/MsBuildProject.cs156
1 files changed, 152 insertions, 4 deletions
diff --git a/src/qtprojectlib/MsBuildProject.cs b/src/qtprojectlib/MsBuildProject.cs
index 77ad72a9..c2429486 100644
--- a/src/qtprojectlib/MsBuildProject.cs
+++ b/src/qtprojectlib/MsBuildProject.cs
@@ -228,6 +228,43 @@ namespace QtProjectLib
}
}
+ /// <summary>
+ /// Parser for project format version string:
+ ///
+ /// QtVS_vNNN
+ ///
+ /// </summary>
+ Parser _ProjectFormatVersion;
+ Parser ProjectFormatVersion
+ {
+ get
+ {
+ if (_ProjectFormatVersion == null) {
+ var expr = "QtVS_v" & new Token("VERSION", Char['0', '9'].Repeat(3))
+ {
+ new Rule<int> { Capture(value => int.Parse(value)) }
+ };
+ try {
+ _ProjectFormatVersion = expr.Render();
+ } catch { }
+ }
+ return _ProjectFormatVersion;
+ }
+ }
+
+ int? ParseProjectFormatVersion(string text)
+ {
+ if (ProjectFormatVersion == null)
+ return null;
+ try {
+ return ProjectFormatVersion.Parse(text)
+ .GetValues<int>("VERSION")
+ .First();
+ } catch {
+ return null;
+ }
+ }
+
const StringComparison IGNORE_CASE = StringComparison.InvariantCultureIgnoreCase;
readonly StringComparer IGNORE_CASE_ = StringComparer.InvariantCultureIgnoreCase;
@@ -266,6 +303,10 @@ namespace QtProjectLib
var projKeyword = globals.Element(ns + "Keyword");
if (projKeyword == null)
return false;
+ var oldVersion = ParseProjectFormatVersion(projKeyword.Value);
+ if (oldVersion.HasValue && oldVersion.Value == Resources.qtProjectFormatVersion)
+ return true; // nothing to do!
+
projKeyword.SetValue(string.Format("QtVS_v{0}", Resources.qtProjectFormatVersion));
// Find import of qt.props
@@ -278,22 +319,129 @@ namespace QtProjectLib
if (qtPropsImport == null)
return false;
+ // Upgrading from v3.0?
+ Dictionary<string, XElement> oldQtInstall = null;
+ Dictionary<string, XElement> oldQtSettings = null;
+ if (oldVersion.HasValue && oldVersion.Value == Resources.qtMinFormatVersion_Settings) {
+ oldQtInstall = this[Files.Project].xml
+ .Elements(ns + "Project")
+ .Elements(ns + "PropertyGroup")
+ .Elements(ns + "QtInstall")
+ .ToDictionary(x => (string)x.Parent.Attribute("Condition"));
+ oldQtInstall.Values.ToList()
+ .ForEach(x => x.Remove());
+
+ oldQtSettings = this[Files.Project].xml
+ .Elements(ns + "Project")
+ .Elements(ns + "PropertyGroup")
+ .Where(x => (string)x.Attribute("Label") == "QtSettings")
+ .ToDictionary(x => (string)x.Attribute("Condition"));
+ oldQtSettings.Values.ToList()
+ .ForEach(x => x.Remove());
+ }
+
// Get project configurations
var configs = this[Files.Project].xml
.Elements(ns + "Project")
.Elements(ns + "ItemGroup")
.Elements(ns + "ProjectConfiguration");
- // Create QtSettings property group immediately after import of qt.props
+ // Find location for import of qt.props and for the QtSettings property group:
+ // (cf. ".vcxproj file elements" https://docs.microsoft.com/en-us/cpp/build/reference/vcxproj-file-structure?view=vs-2019#vcxproj-file-elements)
+ XElement insertionPoint = null;
+
+ // * After the last UserMacros property group
+ insertionPoint = this[Files.Project].xml
+ .Elements(ns + "Project")
+ .Elements(ns + "PropertyGroup")
+ .Where(x => (string)x.Attribute("Label") == "UserMacros")
+ .LastOrDefault();
+
+ // * After the last PropertySheets import group
+ insertionPoint = (insertionPoint != null) ? insertionPoint : this[Files.Project].xml
+ .Elements(ns + "Project")
+ .Elements(ns + "ImportGroup")
+ .Where(x => (string)x.Attribute("Label") == "PropertySheets")
+ .LastOrDefault();
+
+ // * Before the first ItemDefinitionGroup
+ insertionPoint = (insertionPoint != null) ? insertionPoint : this[Files.Project].xml
+ .Elements(ns + "Project")
+ .Elements(ns + "ItemDefinitionGroup")
+ .Select(x => x.ElementsBeforeSelf().Last())
+ .FirstOrDefault();
+
+ // * Before the first ItemGroup
+ insertionPoint = (insertionPoint != null) ? insertionPoint : this[Files.Project].xml
+ .Elements(ns + "Project")
+ .Elements(ns + "ItemGroup")
+ .Select(x => x.ElementsBeforeSelf().Last())
+ .FirstOrDefault();
+
+ // * Before the import of Microsoft.Cpp.targets
+ insertionPoint = (insertionPoint != null) ? insertionPoint : this[Files.Project].xml
+ .Elements(ns + "Project")
+ .Elements(ns + "Import")
+ .Where(x =>
+ (string)x.Attribute("Project") == @"$(VCTargetsPath)\Microsoft.Cpp.targets")
+ .Select(x => x.ElementsBeforeSelf().Last())
+ .FirstOrDefault();
+
+ // * At the end of the file
+ insertionPoint = (insertionPoint != null) ? insertionPoint : this[Files.Project].xml
+ .Elements(ns + "Project")
+ .Elements()
+ .LastOrDefault();
+
+ if (insertionPoint == null)
+ return false;
+
+ // Move import of qt.props to insertion point
+ if (qtPropsImport.Parent.Elements().SingleOrDefault() == qtPropsImport)
+ qtPropsImport.Parent.Remove(); // Remove import group
+ else
+ qtPropsImport.Remove(); // Remove import (group contains other imports)
+ insertionPoint.AddAfterSelf(
+ new XElement(ns + "ImportGroup",
+ new XAttribute("Condition", @"Exists('$(QtMsBuild)\qt.props')"),
+ new XElement(ns + "Import",
+ new XAttribute("Project", @"$(QtMsBuild)\qt.props"))));
+
+ // Create QtSettings property group above import of qt.props
+ var qtSettings = new List<XElement>();
foreach (var config in configs) {
- qtPropsImport.Parent.AddAfterSelf(
- new XElement(ns + "PropertyGroup",
+ var configQtSettings = new XElement(ns + "PropertyGroup",
new XAttribute("Label", "QtSettings"),
new XAttribute("Condition",
string.Format("'$(Configuration)|$(Platform)'=='{0}'",
- (string)config.Attribute("Include")))));
+ (string)config.Attribute("Include"))));
+ insertionPoint.AddAfterSelf(configQtSettings);
+ qtSettings.Add(configQtSettings);
}
+ //// Upgrading from v3.0: move Qt settings to newly created import groups
+ if (oldVersion.HasValue && oldVersion.Value == Resources.qtMinFormatVersion_Settings) {
+ foreach (var configQtSettings in qtSettings) {
+ var configCondition = (string)configQtSettings.Attribute("Condition");
+
+ XElement oldConfigQtInstall;
+ if (oldQtInstall.TryGetValue(configCondition, out oldConfigQtInstall))
+ configQtSettings.Add(oldConfigQtInstall);
+
+ XElement oldConfigQtSettings;
+ if (oldQtSettings.TryGetValue(configCondition, out oldConfigQtSettings)) {
+ foreach (var qtSetting in oldConfigQtSettings.Elements())
+ configQtSettings.Add(qtSetting);
+ }
+ }
+
+ this[Files.Project].isDirty = true;
+ Commit();
+ return true;
+ }
+
+ //// Upgrading from v2.0
+
// Get project user properties (old format)
var userProps = this[Files.Project].xml
.Elements(ns + "Project")