|
15 | 15 | * limitations under the License.
|
16 | 16 | */
|
17 | 17 |
|
18 |
| -import scala.xml.Attribute |
19 |
| -import scala.xml.transform.RewriteRule |
20 |
| -import scala.xml.transform.RuleTransformer |
| 18 | +import scala.sys.process.Process |
| 19 | + |
| 20 | +import sbt.internal.util.Util.isWindows |
21 | 21 |
|
22 | 22 | enablePlugins(JavaAppPackaging)
|
23 | 23 | enablePlugins(RpmPlugin)
|
24 |
| -enablePlugins(WindowsPlugin) |
| 24 | + |
| 25 | +lazy val packageWindowsBin = taskKey[Unit]("Generate windows installer") |
| 26 | +lazy val isccPath = settingKey[String]("Path to the Inno Setup ISCC.exe file") |
25 | 27 |
|
26 | 28 | executableScriptName := "daffodil"
|
27 | 29 |
|
28 | 30 | Universal / packageName := "apache-daffodil-" + version.value + "-bin" //tarball name
|
29 | 31 | Linux / packageName := executableScriptName.value
|
30 | 32 | Rpm / packageName := "apache-" + executableScriptName.value
|
31 |
| -Windows / packageName := executableScriptName.value |
32 | 33 |
|
33 | 34 | val optSourceDateEpoch = scala.util.Properties.envOrNone("SOURCE_DATE_EPOCH")
|
34 | 35 |
|
@@ -158,184 +159,47 @@ rpmPrefix := Some(defaultLinuxInstallLocation.value)
|
158 | 159 | // Windows configuration
|
159 | 160 | //
|
160 | 161 |
|
161 |
| -// |
162 |
| -// Here we set the variables that are supported by the sbt Native Packager plug-in. |
163 |
| -// We also get fairly aggressive in editing/modifying the XML in order |
164 |
| -// to control and use some specific features that are supported by WiX |
165 |
| -// but which are not properly suported by the sbt plug-in. |
166 |
| -// |
167 |
| - |
168 |
| -// Force the correct installation directory name. This overwrites |
169 |
| -// 'daffodil-cli', which is the directory that we invoke sbt in. |
170 |
| -// The sbt WiX plug-in incorrectly assumes that the directory of |
171 |
| -// invocation is the same name as the direcotry you eventually |
172 |
| -// want to install into. |
173 |
| -Windows / name := "Daffodil" |
174 |
| - |
175 |
| -// The Windows packager sbt plug-in maps the packageSummary variable |
176 |
| -// into the WiX productName field. Another strange choice. |
177 |
| -Windows / packageSummary := "Daffodil" |
178 |
| - |
179 |
| -// The Windows packager sbt plug-in limits the length of the packageDescription |
180 |
| -// field to a single line. Use the short packageSummary from the RPM config. |
181 |
| -Windows / packageDescription := (Rpm / packageSummary).value |
182 |
| - |
183 |
| -// Use the same version number as in the rpm, which has SNAPSHOT removed if it |
184 |
| -// exists. Windows version numbers has no concept of a "snapshot build", only |
185 |
| -// major, minor, patch, and build. So Windows MSI versions do not differentiate |
186 |
| -// between snapshots and non-snapshots. |
187 |
| -Windows / version := (Rpm / version).value |
188 |
| - |
189 |
| -// Required and critical GUIDs. Ironically the ProductId is unique |
190 |
| -// to a given release, but UpgradeId must NEVER change! This may |
191 |
| -// seem conter-intuitive, but the UpgradeId is actually what ties |
192 |
| -// the product to it's upgrades and the product is actually unique |
193 |
| -// each time it is released, so there is some semblance of logic |
194 |
| -// to this scheme. |
195 |
| -wixProductUpgradeId := "4C966AFF-585E-4E17-8CC2-059FD70FEC77" |
196 |
| - |
197 |
| -// Light options. Bring in standard dialog boxes and localization. |
198 |
| -// The suppression of ICE61 is required as we *DO* permit |
199 |
| -// re-installation of the same version. Despite the presence of |
200 |
| -// specific XML to enable this, the WiX compiler and linker |
201 |
| -// complain about it unless you specifically suppress the warning. |
202 |
| -lightOptions ++= Seq( |
203 |
| - "-sval", // validation does not currently work under Wine, this disables that |
204 |
| - "-sice:ICE61", |
205 |
| - "-loc", |
206 |
| - ((Windows / sourceDirectory).value / "Product_en-us.wxl").toString |
207 |
| -) |
208 |
| - |
209 |
| -// Build an RTF version of the license file for display in the license |
210 |
| -// acceptance dialog box. This file will also be sent to the |
211 |
| -// printer when and if the user asks for hard copy via the 'print' button. |
212 |
| -wixProductLicense := { |
213 |
| - // Make sure the target direcotry exists. |
214 |
| - (Windows / target).value.mkdirs() |
215 |
| - |
216 |
| - // This target file doesn't exist until placed there by the build. |
217 |
| - val targetLicense = (Windows / target).value / "LICENSE.rtf" |
218 |
| - val sourceLicense = baseDirectory.value / "bin.LICENSE" |
219 |
| - // somehow convert sourceLicense into RTF and store at targetLicense |
220 |
| - val rtfHeader = """{\rtf {\fonttbl {\f0 Arial;}} \f0\fs18""" |
221 |
| - val rtfFooter = """}""" |
222 |
| - |
223 |
| - val licenseLines = scala.io.Source.fromFile(sourceLicense, "UTF-8").getLines |
224 |
| - val writer = new java.io.PrintWriter(targetLicense, "UTF-8") |
225 |
| - // windows style line endings in the license are required by the WiX toolkit |
226 |
| - writer.write(rtfHeader + "\r\n") |
227 |
| - licenseLines.foreach { line => |
228 |
| - writer.write(line + """\line""" + "\r\n") |
229 |
| - } |
230 |
| - writer.write(rtfFooter + "\r\n") |
231 |
| - writer.close |
232 |
| - Option(targetLicense) |
233 |
| -} |
234 |
| - |
235 |
| -// Use the wixFiles variable to add in the Daffodil-specific dialog |
236 |
| -// boxes and sequence. |
237 |
| -wixFiles ++= Seq( |
238 |
| - (Windows / sourceDirectory).value / "WixUI_Daffodil.wxs" |
239 |
| -) |
240 |
| - |
241 |
| -// The sbt Native Packager plug-in assumes that we want to give the user |
242 |
| -// a Feature Tree to select from. One of the 'features' that the plug-in |
243 |
| -// offers up is a set of all shortcuts and menu links. Daffodil is |
244 |
| -// actually a command-line executable, so we do not include |
245 |
| -// configuration links as they are unnecessary. From a practical |
246 |
| -// standpoint the user must invoke a command shell in a window |
247 |
| -// before they can invoke Daffodil anyway. |
248 |
| -wixFeatures := { |
249 |
| - val features = wixFeatures.value |
250 |
| - features.filter { _.id != "AddConfigLinks" } |
| 162 | +/** |
| 163 | + * If building on a non-Windows machine, uses winepath to convert a Unix file path to a Windows |
| 164 | + * path that can be used with wine. If this is Windows, just return the file path as a string |
| 165 | + */ |
| 166 | +def winpath(file: File): String = { |
| 167 | + if (isWindows) file.toString |
| 168 | + else Process(Seq("winepath", "-w", file.toString)).!! |
251 | 169 | }
|
252 | 170 |
|
253 |
| -// Make sure that we don't use an MSI installer that is older than |
254 |
| -// version 2.0. It also fixes the comment attribute that hangs |
255 |
| -// out on the Package keyword. |
256 |
| -wixPackageInfo := wixPackageInfo.value.copy( |
257 |
| - installerVersion = "200", |
258 |
| - comments = "!(loc.Comments)" |
259 |
| -) |
260 |
| - |
261 |
| -// Fix the XML that is associated with the installable files and directories. |
262 |
| -wixProductConfig := { |
263 |
| - // Pick up the generated code. |
264 |
| - val pc = wixProductConfig.value |
265 |
| - |
266 |
| - // Replace the default headline banner and Welcome/Exit screen |
267 |
| - // bitmaps with the custom ones we developed for Daffodil. |
268 |
| - val banner = <WixVariable Id="WixUIBannerBmp" Value={ |
269 |
| - ((Windows / sourceDirectory).value / "banner.bmp").toString |
270 |
| - } /> |
271 |
| - val dialog = <WixVariable Id="WixUIDialogBmp" Value={ |
272 |
| - ((Windows / sourceDirectory).value / "dialog.bmp").toString |
273 |
| - } /> |
274 |
| - |
275 |
| - // Reference the Daffodil-specific User Interface (dialog box) sequence. |
276 |
| - val ui = <UI><UIRef Id="WixUI_Daffodil" /></UI> |
277 |
| - |
278 |
| - // Make sure we abort if we are not installing on Windows 95 or later. |
279 |
| - val osCondition = |
280 |
| - <Condition Message="!(loc.OS2Old)"><![CDATA[Installed OR (VersionNT >= 400)]]></Condition> |
281 |
| - |
282 |
| - // Define icons (ID should not be longer than 18 chars and must end with ".exe") |
283 |
| - val icon = Seq( |
284 |
| - <Icon Id="Daffodil.ico" SourceFile={ |
285 |
| - ((Windows / sourceDirectory).value / "apache-daffodil.ico").toString |
286 |
| - } />, |
287 |
| - <Property Id="ARPPRODUCTICON" Value="Daffodil.ico" /> |
288 |
| - ) |
289 |
| - |
290 |
| - // String together the additional XML around the generated directory and file lists. |
291 |
| - val pcGroup = pc.asInstanceOf[scala.xml.Group] |
292 |
| - val newNodes = osCondition ++ icon ++ pcGroup.nodes ++ dialog ++ banner ++ ui |
293 |
| - val pcWithNewNodes = pcGroup.copy(nodes = newNodes) |
294 |
| - |
295 |
| - // Change (edit) some items inside the directory/files list. |
296 |
| - val pcRewriteRule = new RewriteRule { |
297 |
| - override def transform(n: scala.xml.Node): Seq[scala.xml.Node] = n match { |
298 |
| - |
299 |
| - // We want to comply with the Windows standard pattern of |
300 |
| - // installing at /Program Files/ManufacturerName/Application |
301 |
| - // This case effectively inserts the manufacturer name into |
302 |
| - // the XML as a directory to comply with the standard. |
303 |
| - case e: scala.xml.Elem if (e \ "@Name").text == "PFiles" => { |
304 |
| - val apacheDir = <Directory Id="ProgramFilesApache" Name="!(loc.ManufacturerName)" /> |
305 |
| - val apacheDirWithChild = apacheDir.copy(child = e.child) |
306 |
| - e.copy(child = apacheDirWithChild) |
307 |
| - } |
308 |
| - |
309 |
| - // We *ARE* going to allow the user to repair and reinstall |
310 |
| - // the same exact version, so we need to add an attribute |
311 |
| - // to the MajorUpgrade keyword. This will trigger an 'ICE61' |
312 |
| - // error that we suppress on the 'light' linker command line. |
313 |
| - case e: scala.xml.Elem if e.label == "MajorUpgrade" => { |
314 |
| - e % scala.xml.Attribute("", "AllowSameVersionUpgrades", "yes", e.attributes) |
315 |
| - } |
316 |
| - |
317 |
| - // Fixup for registry key. |
318 |
| - case e: scala.xml.Elem if e.label == "RegistryValue" => { |
319 |
| - val attribs = e.attributes.remove("Key") |
320 |
| - e % scala.xml.Attribute( |
321 |
| - "", |
322 |
| - "Key", |
323 |
| - """Software\Apache\Installed Products\Daffodil""", |
324 |
| - attribs |
325 |
| - ) |
326 |
| - } |
327 |
| - |
328 |
| - // The WixUI_FeatureTree reference has to be removed so that |
329 |
| - // our custom Daffodil UI can operate properly. |
330 |
| - case e: scala.xml.Elem |
331 |
| - if e.label == "UIRef" && (e \ "@Id").text == "WixUI_FeatureTree" => { |
332 |
| - scala.xml.NodeSeq.Empty |
333 |
| - } |
334 |
| - case `n` => n |
| 171 | +/** |
| 172 | + * Set the default path to the ISCC compiler to the Windows path. Since we run it with wine on |
| 173 | + * Linux, this path should work on both Windows and Linux. Depending on the wine config, windows |
| 174 | + * version, or how Inno Setup is installed, this might need to be set to a different value. |
| 175 | + */ |
| 176 | +isccPath := "C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe" |
| 177 | + |
| 178 | +packageWindowsBin := { |
| 179 | + (Universal / stage).value |
| 180 | + |
| 181 | + // if SOURCE_DATE_EPOCH is defined, then we use that as the TouchDate/Time settings to set |
| 182 | + // embedded timestamps, which allows for reproducible builds |
| 183 | + val (touchDate, touchTime) = optSourceDateEpoch |
| 184 | + .map { epoch => |
| 185 | + val fmt = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss") |
| 186 | + fmt.setTimeZone(java.util.TimeZone.getTimeZone("UTC")) |
| 187 | + val time = fmt.format(new java.util.Date(epoch.toLong * 1000)) |
| 188 | + val dateTime = time.split(" ") |
| 189 | + (dateTime(0), dateTime(1)) |
335 | 190 | }
|
336 |
| - } |
337 |
| - |
338 |
| - // Now apply all the edits in the RewriteRule defined above. |
339 |
| - val newXml = new RuleTransformer(pcRewriteRule).transform(pcWithNewNodes) |
340 |
| - <xml:group>{newXml}</xml:group> |
| 191 | + .getOrElse(("current", "current")) |
| 192 | + |
| 193 | + val optWine = if (!isWindows) Some("wine") else None |
| 194 | + val isccCmd = optWine ++: Seq( |
| 195 | + isccPath.value, |
| 196 | + "/O" + winpath(target.value / "windows"), |
| 197 | + "/F" + (Universal / packageName).value, |
| 198 | + "/DVERSION=" + version.value, |
| 199 | + "/DBASEDIR=" + winpath(baseDirectory.value), |
| 200 | + "/DTOUCHDATE=" + touchDate, |
| 201 | + "/DTOUCHTIME=" + touchTime, |
| 202 | + winpath(baseDirectory.value / "src" / "windows" / "apache-daffodil.iss") |
| 203 | + ) |
| 204 | + Process(isccCmd).!! |
341 | 205 | }
|
0 commit comments