@joebigelow / wix-1 / commits / 7d41de1a

Handle references to standard directories

Closes 7072

Rob Mensching committed Dec 8, 2022 at 16:59 UTC 7d41de1a726038d71873db48e9f5a575578679f5
2 files changed +136 -45
src/wix/WixToolset.Converters/WixConverter.cs
+56 -45
@@ -1094,40 +1094,18 @@ namespace WixToolset.Converters
1094
1095 var id = element.Attribute("Id")?.Value;
1096
1097 - if (id == "TARGETDIR" &&
1098 - this.OnInformation(ConverterTestType.TargetDirDeprecated, element, "The TARGETDIR directory should not longer be explicitly defined. Remove the Directory element with Id attribute 'TARGETDIR'."))
1097 + if (id == "TARGETDIR")
1098 {
1100 - var parentElement = element.Parent;
1101 -
1102 - element.Remove();
1103 -
1104 - if (parentElement.FirstNode is XText text && String.IsNullOrWhiteSpace(text.Value))
1105 - {
1106 - parentElement.FirstNode.Remove();
1107 - }
1108 -
1109 - foreach (var child in element.Nodes())
1099 + if (this.OnInformation(ConverterTestType.TargetDirDeprecated, element, "The TARGETDIR directory should no longer be explicitly defined. Remove the Directory element with Id attribute 'TARGETDIR'."))
1100 {
1111 - parentElement.Add(child);
1112 - }
1113 -
1114 - element.RemoveAll();
1115 -
1116 - if (parentElement.FirstNode is XText textAgain && String.IsNullOrWhiteSpace(textAgain.Value))
1117 - {
1118 - parentElement.FirstNode.Remove();
1101 + RemoveElementKeepChildren(element);
1102 }
1103 }
1104 else if (id != null &&
1105 WindowsInstallerStandard.IsStandardDirectory(id) &&
1106 this.OnInformation(ConverterTestType.DefiningStandardDirectoryDeprecated, element, "Standard directories such as '{0}' should no longer be defined using the Directory element. Use the StandardDirectory element instead.", id))
1107 {
1125 - element.Name = StandardDirectoryElementName;
1126 -
1127 - foreach (var attrib in element.Attributes().Where(a => a.Name.LocalName != "Id").ToList())
1128 - {
1129 - attrib.Remove();
1130 - }
1108 + RenameElementToStandardDirectory(element);
1109 }
1110 }
1111
@@ -1135,28 +1113,22 @@ namespace WixToolset.Converters
1113 {
1114 var id = element.Attribute("Id")?.Value;
1115
1138 - if (id == "TARGETDIR" &&
1139 - this.OnInformation(ConverterTestType.TargetDirRefDeprecated, element, "The TARGETDIR directory should not longer be explicitly referenced. Remove the DirectoryRef element with Id attribute 'TARGETDIR'."))
1116 + if (id != null && WindowsInstallerStandard.IsStandardDirectory(id))
1117 {
1141 - var parentElement = element.Parent;
1142 -
1143 - element.Remove();
1144 -
1145 - if (parentElement.FirstNode is XText text && String.IsNullOrWhiteSpace(text.Value))
1118 + if (!element.HasElements)
1119 {
1147 - parentElement.FirstNode.Remove();
1120 + this.OnError(ConverterTestType.EmptyStandardDirectoryRefNotConvertable, element, "Referencing '{0}' directory directly is no longer supported. The DirectoryRef will not be removed but you will probably need to reference a more specific directory.", id);
1121 }
1149 -
1150 - foreach (var child in element.Nodes())
1122 + else if (id == "TARGETDIR")
1123 {
1152 - parentElement.Add(child);
1124 + if (this.OnInformation(ConverterTestType.StandardDirectoryRefDeprecated, element, "The {0} directory should no longer be explicitly referenced. Remove the DirectoryRef element with Id attribute '{0}'.", id))
1125 + {
1126 + RemoveElementKeepChildren(element);
1127 + }
1128 }
1154 -
1155 - element.RemoveAll();
1156 -
1157 - if (parentElement.FirstNode is XText textAgain && String.IsNullOrWhiteSpace(textAgain.Value))
1129 + else if (this.OnInformation(ConverterTestType.StandardDirectoryRefDeprecated, element, "The standard directory '{0}' should no longer be directly referenced. Use the StandardDirectory element instead.", id))
1130 {
1159 - parentElement.FirstNode.Remove();
1131 + RenameElementToStandardDirectory(element);
1132 }
1133 }
1134 }
@@ -2725,6 +2697,40 @@ namespace WixToolset.Converters
2697 return value;
2698 }
2699
2700 + private static void RemoveElementKeepChildren(XElement element)
2701 + {
2702 + var parentElement = element.Parent;
2703 +
2704 + element.Remove();
2705 +
2706 + if (parentElement.FirstNode is XText text && String.IsNullOrWhiteSpace(text.Value))
2707 + {
2708 + parentElement.FirstNode.Remove();
2709 + }
2710 +
2711 + foreach (var child in element.Nodes())
2712 + {
2713 + parentElement.Add(child);
2714 + }
2715 +
2716 + element.RemoveAll();
2717 +
2718 + if (parentElement.FirstNode is XText textAgain && String.IsNullOrWhiteSpace(textAgain.Value))
2719 + {
2720 + parentElement.FirstNode.Remove();
2721 + }
2722 + }
2723 +
2724 + private static void RenameElementToStandardDirectory(XElement element)
2725 + {
2726 + element.Name = StandardDirectoryElementName;
2727 +
2728 + foreach (var attrib in element.Attributes().Where(a => a.Name.LocalName != "Id").ToList())
2729 + {
2730 + attrib.Remove();
2731 + }
2732 + }
2733 +
2734 private static bool TryGetInnerText(XElement element, out string value, out List<XNode> comments)
2735 {
2736 return TryGetInnerText(element, out value, out comments, new List<XNode>());
@@ -3138,7 +3144,7 @@ namespace WixToolset.Converters
3144 SoftwareTagTypeObsolete,
3145
3146 /// <summary>
3141 - /// TARGETDIR directory should not longer be explicitly defined.
3147 + /// TARGETDIR directory should no longer be explicitly defined.
3148 /// </summary>
3149 TargetDirDeprecated,
3150
@@ -3178,9 +3184,14 @@ namespace WixToolset.Converters
3184 CustomActionIdsIncludePlatformSuffix,
3185
3186 /// <summary>
3181 - /// The TARGETDIR directory should not longer be explicitly referenced.
3187 + /// The {0} directory should no longer be explicitly referenced. Remove the DirectoryRef element with Id attribute '{0}'.
3188 + /// </summary>
3189 + StandardDirectoryRefDeprecated,
3190 +
3191 + /// <summary>
3192 + /// Referencing '{0}' directory directly is no longer supported. The DirectoryRef will not be removed but you will probably need to reference a more specific directory.
3193 /// </summary>
3183 - TargetDirRefDeprecated,
3194 + EmptyStandardDirectoryRefNotConvertable,
3195 }
3196 }
3197 }
src/wix/test/WixToolsetTest.Converters/DirectoryFixture.cs
+80
@@ -3,6 +3,7 @@
3 namespace WixToolsetTest.Converters
4 {
5 using System;
6 + using System.Linq;
7 using System.Xml.Linq;
8 using WixInternal.TestSupport;
9 using WixToolset.Converters;
@@ -129,6 +130,42 @@ namespace WixToolsetTest.Converters
130 Assert.Equal(4, errors);
131 }
132
133 + [Fact]
134 + public void FixStandardDirectoryRef()
135 + {
136 + var parse = String.Join(Environment.NewLine,
137 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
138 + "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>",
139 + " <Fragment>",
140 + " <DirectoryRef Id='ProgramFilesFolder'>",
141 + " <Directory Id='ChildFolder' Name='Child' />",
142 + " </DirectoryRef>",
143 + " </Fragment>",
144 + "</Wix>");
145 +
146 + var expected = new[]
147 + {
148 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
149 + " <Fragment>",
150 + " <StandardDirectory Id=\"ProgramFilesFolder\">",
151 + " <Directory Id=\"ChildFolder\" Name=\"Child\" />",
152 + " </StandardDirectory>",
153 + " </Fragment>",
154 + "</Wix>"
155 + };
156 +
157 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
158 +
159 + var messaging = new MockMessaging();
160 + var converter = new WixConverter(messaging, 2, null, null);
161 +
162 + var errors = converter.ConvertDocument(document);
163 +
164 + var actualLines = UnformattedDocumentLines(document);
165 + WixAssert.CompareLineByLine(expected, actualLines);
166 + Assert.Equal(3, errors);
167 + }
168 +
169 [Fact]
170 public void RemoveTargetDirRefAndFixStandardDirectory()
171 {
@@ -166,5 +203,48 @@ namespace WixToolsetTest.Converters
203 WixAssert.CompareLineByLine(expected, actualLines);
204 Assert.Equal(4, errors);
205 }
206 +
207 + [Fact]
208 + public void ErrorOnEmptyStandardDirectoryRef()
209 + {
210 + var parse = String.Join(Environment.NewLine,
211 + "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>",
212 + " <Fragment>",
213 + " <DirectoryRef Id='TARGETDIR' />",
214 + " <DirectoryRef Id='ProgramFilesFolder' />",
215 + " <DirectoryRef Id='DesktopFolder' />",
216 + " </Fragment>",
217 + "</Wix>");
218 +
219 + var expected = new[]
220 + {
221 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
222 + " <Fragment>",
223 + " <DirectoryRef Id=\"TARGETDIR\" />",
224 + " <DirectoryRef Id=\"ProgramFilesFolder\" />",
225 + " <DirectoryRef Id=\"DesktopFolder\" />",
226 + " </Fragment>",
227 + "</Wix>"
228 + };
229 +
230 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
231 +
232 + var messaging = new MockMessaging();
233 + var converter = new WixConverter(messaging, 2, null, null);
234 +
235 + var errors = converter.ConvertDocument(document);
236 +
237 + WixAssert.CompareLineByLine(new[]
238 + {
239 + "[Converted] The namespace 'http://schemas.microsoft.com/wix/2006/wi' is out of date. It must be 'http://wixtoolset.org/schemas/v4/wxs'. (XmlnsValueWrong)",
240 + "Referencing 'TARGETDIR' directory directly is no longer supported. The DirectoryRef will not be removed but you will probably need to reference a more specific directory. (EmptyStandardDirectoryRefNotConvertable)",
241 + "Referencing 'ProgramFilesFolder' directory directly is no longer supported. The DirectoryRef will not be removed but you will probably need to reference a more specific directory. (EmptyStandardDirectoryRefNotConvertable)",
242 + "Referencing 'DesktopFolder' directory directly is no longer supported. The DirectoryRef will not be removed but you will probably need to reference a more specific directory. (EmptyStandardDirectoryRefNotConvertable)"
243 + }, messaging.Messages.Select(m => m.ToString()).ToArray());
244 +
245 + var actualLines = UnformattedDocumentLines(document);
246 + WixAssert.CompareLineByLine(expected, actualLines);
247 + Assert.Equal(4, errors);
248 + }
249 }
250 }