aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Extensibility/HeatExtension.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/Extensibility/HeatExtension.cs')
-rw-r--r--src/WixToolset.Core/Extensibility/HeatExtension.cs204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Extensibility/HeatExtension.cs b/src/WixToolset.Core/Extensibility/HeatExtension.cs
new file mode 100644
index 00000000..5e292220
--- /dev/null
+++ b/src/WixToolset.Core/Extensibility/HeatExtension.cs
@@ -0,0 +1,204 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Extensibility
4{
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Reflection;
9 using WixToolset;
10 using WixToolset.Data;
11 using WixToolset.Extensibilty;
12 using WixToolset.Tools;
13 using Wix = WixToolset.Data.Serialize;
14
15 /// <summary>
16 /// A command line option.
17 /// </summary>
18 public struct HeatCommandLineOption
19 {
20 public string Option;
21
22 public string Description;
23
24 /// <summary>
25 /// Instantiates a new CommandLineOption.
26 /// </summary>
27 /// <param name="option">The option name.</param>
28 /// <param name="description">The description of the option.</param>
29 public HeatCommandLineOption(string option, string description)
30 {
31 this.Option = option;
32 this.Description = description;
33 }
34 }
35
36 /// <summary>
37 /// An extension for the WiX Toolset Harvester application.
38 /// </summary>
39 public abstract class HeatExtension
40 {
41 /// <summary>
42 /// Gets or sets the heat core for the extension.
43 /// </summary>
44 /// <value>The heat core for the extension.</value>
45 public IHeatCore Core { get; set; }
46
47 /// <summary>
48 /// Gets the supported command line types for this extension.
49 /// </summary>
50 /// <value>The supported command line types for this extension.</value>
51 public virtual HeatCommandLineOption[] CommandLineTypes
52 {
53 get { return null; }
54 }
55
56 /// <summary>
57 /// Loads a HeatExtension from a type description string.
58 /// </summary>
59 /// <param name="extension">The extension type description string.</param>
60 /// <returns>The loaded HeatExtension.</returns>
61 /// <remarks>
62 /// <paramref name="extension"/> can be in several different forms:
63 /// <list type="number">
64 /// <item><term>AssemblyQualifiedName (TopNamespace.SubNameSpace.ContainingClass+NestedClass, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089)</term></item>
65 /// <item><term>AssemblyName (MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089)</term></item>
66 /// <item><term>Absolute path to an assembly (C:\MyExtensions\ExtensionAssembly.dll)</term></item>
67 /// <item><term>Filename of an assembly in the application directory (ExtensionAssembly.dll)</term></item>
68 /// <item><term>Relative path to an assembly (..\..\MyExtensions\ExtensionAssembly.dll)</term></item>
69 /// </list>
70 /// To specify a particular class to use, prefix the fully qualified class name to the assembly and separate them with a comma.
71 /// For example: "TopNamespace.SubNameSpace.ContainingClass+NestedClass, C:\MyExtensions\ExtensionAssembly.dll"
72 /// </remarks>
73 public static HeatExtension Load(string extension)
74 {
75 Type extensionType = null;
76 int commaIndex = extension.IndexOf(',');
77 string className = String.Empty;
78 string assemblyName = extension;
79
80 if (0 <= commaIndex)
81 {
82 className = extension.Substring(0, commaIndex);
83 assemblyName = (extension.Length <= commaIndex + 1 ? String.Empty : extension.Substring(commaIndex + 1));
84 }
85
86 className = className.Trim();
87 assemblyName = assemblyName.Trim();
88
89 if (null == extensionType && 0 < assemblyName.Length)
90 {
91
92 Assembly extensionAssembly;
93
94 // case 3: Absolute path to an assembly
95 if (Path.IsPathRooted(assemblyName))
96 {
97 extensionAssembly = ExtensionLoadFrom(assemblyName);
98 }
99 else
100 {
101 try
102 {
103 // case 2: AssemblyName
104 extensionAssembly = Assembly.Load(assemblyName);
105 }
106 catch (IOException e)
107 {
108 if (e is FileLoadException || e is FileNotFoundException)
109 {
110 try
111 {
112 // case 4: Filename of an assembly in the application directory
113 extensionAssembly = Assembly.Load(Path.GetFileNameWithoutExtension(assemblyName));
114 }
115 catch (IOException innerE)
116 {
117 if (innerE is FileLoadException || innerE is FileNotFoundException)
118 {
119 // case 5: Relative path to an assembly
120
121 // we want to use Assembly.Load when we can because it has some benefits over Assembly.LoadFrom
122 // (see the documentation for Assembly.LoadFrom). However, it may fail when the path is a relative
123 // path, so we should try Assembly.LoadFrom one last time. We could have detected a directory
124 // separator character and used Assembly.LoadFrom directly, but dealing with path canonicalization
125 // issues is something we don't want to deal with if we don't have to.
126 extensionAssembly = ExtensionLoadFrom(assemblyName);
127 }
128 else
129 {
130 throw new WixException(WixErrors.InvalidExtension(assemblyName, innerE.Message));
131 }
132 }
133 }
134 else
135 {
136 throw new WixException(WixErrors.InvalidExtension(assemblyName, e.Message));
137 }
138 }
139 }
140
141 if (0 < className.Length)
142 {
143 try
144 {
145 // case 1: AssemblyQualifiedName
146 extensionType = extensionAssembly.GetType(className, true /* throwOnError */, true /* ignoreCase */);
147 }
148 catch (Exception e)
149 {
150 throw new WixException(WixErrors.InvalidExtensionType(assemblyName, className, e.GetType().ToString(), e.Message));
151 }
152 }
153 else
154 {
155 // if no class name was specified, then let's hope the assembly defined a default WixExtension
156 AssemblyDefaultHeatExtensionAttribute extensionAttribute = (AssemblyDefaultHeatExtensionAttribute)Attribute.GetCustomAttribute(extensionAssembly, typeof(AssemblyDefaultHeatExtensionAttribute));
157
158 if (null != extensionAttribute)
159 {
160 extensionType = extensionAttribute.ExtensionType;
161 }
162 else
163 {
164 throw new WixException(WixErrors.InvalidExtensionType(assemblyName, typeof(AssemblyDefaultHeatExtensionAttribute).ToString()));
165 }
166 }
167 }
168
169 if (extensionType.IsSubclassOf(typeof(HeatExtension)))
170 {
171 return Activator.CreateInstance(extensionType) as HeatExtension;
172 }
173 else
174 {
175 throw new WixException(WixErrors.InvalidExtensionType(extension, extensionType.ToString(), typeof(HeatExtension).ToString()));
176 }
177 }
178
179 /// <summary>
180 /// Parse the command line options for this extension.
181 /// </summary>
182 /// <param name="type">The active harvester type.</param>
183 /// <param name="args">The option arguments.</param>
184 public virtual void ParseOptions(string type, string[] args)
185 {
186 }
187
188 private static Assembly ExtensionLoadFrom(string assemblyName)
189 {
190 Assembly extensionAssembly = null;
191
192 try
193 {
194 extensionAssembly = Assembly.LoadFrom(assemblyName);
195 }
196 catch (Exception e)
197 {
198 throw new WixException(WixErrors.InvalidExtension(assemblyName, e.Message));
199 }
200
201 return extensionAssembly;
202 }
203 }
204}