1
- #! /bin/sh -x
1
+ #! /bin/sh
2
+ #
3
+ # package-msi: Build Windows MSI installer package for CFEngine using WiX Toolset
4
+ # This script creates a Windows installer (.msi) file for CFEngine Nova
5
+ # It handles both x86 (32-bit) and x64 (64-bit) architectures
2
6
7
+ # Source common build functions and environment configuration
3
8
. " $( dirname " $0 " ) " /functions
4
9
. detect-environment
5
10
. compile-options
6
11
. version
7
12
13
+ # Path where WiX toolset binaries will be installed
8
14
WIXPATH=" $HOME /wix"
9
15
10
- # First see if wix tools are installed, if not, do so
16
+ # Check if WiX tools are installed, install them if not present
17
+ log_debug " Checking for WiX tools at $WIXPATH "
11
18
if [ -f " $WIXPATH /candle.exe" ] && [ -f " $WIXPATH /light.exe" ]; then
12
- echo " Wix Tools are installed at $WIXPATH "
19
+ log_debug " WiX tools found - candle.exe and light.exe are present "
13
20
else
21
+ log_debug " WiX tools not found - starting installation"
14
22
(
15
- # Fetch some prerequisites
23
+ # Download prerequisites from build artifacts cache server
16
24
cd /tmp || exit
17
25
echo '
18
26
get /export/images/windows/wix310-binaries.zip
19
27
get /export/images/windows/wine-folder.tar.xz
20
28
' | sftp -b - jenkins_sftp_cache@build-artifacts-cache.cloud.cfengine.com
21
29
22
- # check checksums
30
+ # Verify downloaded files
23
31
sha256sum -c - << EOF || exit 42
24
32
493145b3fac22bdf8c55142a9f96ef8136d56b38d78a2322f13f1ba11f9cf2f8 wix310-binaries.zip
25
33
3510fd8c4ecb4a9c479dfe43849183c666f9e41b019fc7135dc8735d0032d16e wine-folder.tar.xz
26
34
EOF
27
- # Install Wix tools
35
+ # Install WiX Toolset binaries
28
36
mkdir -p " $WIXPATH "
29
37
cd " $WIXPATH " || exit
30
38
unzip /tmp/wix310-binaries.zip
31
39
chown " $USER " :" $USER " -R " $WIXPATH "
32
40
33
- # Extract pre-installed Wine .NET tree
34
- # This file was generated by using a fresh Wine installation and running "winetricks dotnet45".
41
+ # Extract pre-configured Wine environment with .NET Framework
42
+ # This archive contains a Wine prefix with dotnet45 already installed
43
+ # (created by running "winetricks dotnet45" on a fresh Wine installation)
35
44
cd " $HOME " || exit
36
45
tar -xJf /tmp/wine-folder.tar.xz
37
46
chown " $USER " :" $USER " -R " $HOME " /.wine
41
50
)
42
51
fi
43
52
44
- # Wine can handle these tools under the following conditions :
53
+ # Wine configuration requirements for running WiX tools :
45
54
# * You must use Wine 32-bit (wine:i386)
46
55
# * The host must have run "winetricks dotnet45" and clicked through all the
47
56
# installations.
48
57
#
49
- # This was tested with Wix tools 3.10.
58
+ # This was tested with WiX tools 3.10.
59
+ # Define WiX tool commands - candle.exe compiles .wxs files, light.exe links them
60
+ #
61
+ # TODO: ENT-13249: candle.exe and light.exe have been replaced with the single WiX build command.
50
62
CANDLE=" wine $WIXPATH /candle.exe"
51
63
LIGHT=" wine $WIXPATH /light.exe"
52
64
65
+ # Determine build directory name based on Jenkins job or version/arch
66
+ log_debug " Determining build directory name (JOB_NAME=$JOB_NAME , VERSION=$VERSION , ARCH=$ARCH )"
53
67
if [ -z " $JOB_NAME " ]; then
54
68
DIRNAME=build-$VERSION -$ARCH
69
+ log_debug " No JOB_NAME set, using DIRNAME=$DIRNAME "
55
70
else
71
+ # Extract first part of Jenkins job name (before the slash)
56
72
DIRNAME=$( echo " ${JOB_NAME} " | sed ' s/\(.*\)\/.*/\1/g' )
73
+ log_debug " Using Jenkins job name, DIRNAME=$DIRNAME "
57
74
fi
58
75
76
+ # Set up packaging directory paths
59
77
PKGD=$BASEDIR /packaging/cfengine-nova/pkg
60
78
P=$PKGD /$DIRNAME
61
79
80
+ # pre() - Prepare the packaging directory structure and copy all required files
81
+ # This function sets up the directory layout for the MSI package build
62
82
pre () {
83
+ log_debug " Preparing packaging directory structure"
84
+
85
+ # Clean up any existing packaging directory and create fresh structure
86
+ log_debug " Removing existing packaging directory: $PKGD "
63
87
rm -rf " $PKGD "
64
88
mkdir -p " $P " /bin
65
89
mkdir -p " $P " /ssl
66
90
91
+ # Copy CFEngine binaries and SSL files from build prefix
92
+ log_debug " Copying binaries from $BUILDPREFIX /bin to $P /bin"
67
93
cp -a " $BUILDPREFIX " /bin/* " $P " /bin
94
+ log_debug " Copying SSL files from $BUILDPREFIX /ssl to $P /ssl"
68
95
cp -a " $BUILDPREFIX " /ssl/* " $P " /ssl
96
+ log_debug " Copying dist binaries from $BASEDIR /cfengine/dist$BUILDPREFIX /bin"
69
97
cp -a " $BASEDIR " /cfengine/dist" $BUILDPREFIX " /bin/* " $P " /bin
70
98
71
- # TODO make not hard-coded paths for debian/ubuntu installations of mingw
72
- # I couldn't find an easy way to dynamically find the path to this dll so hard-coded
73
- # it is. :(
99
+ # Copy MinGW runtime DLL and architecture-specific event DLL
100
+ # TODO: make not hard-coded paths for debian/ubuntu installations of mingw
101
+ # These paths are currently hard-coded as there's no easy way to dynamically find them
102
+ log_debug " Copying MinGW runtime DLLs for architecture: $ARCH "
74
103
case " $ARCH " in
75
104
x86)
105
+ # 32-bit: Copy i686 MinGW pthread DLL and 32-bit event DLL
76
106
cp -a /usr/i686-w64-mingw32/lib/libwinpthread-1.dll " $P " /bin/libwinpthread-1.dll
77
107
cp -a " $BASEDIR " /enterprise/libcfenterprise/cf.events.i686.dll " $P " /bin/cf.events.dll
78
108
;;
79
109
x64)
110
+ # 64-bit: Copy x86_64 MinGW pthread DLL and 64-bit event DLL
80
111
cp -a /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll " $P " /bin/libwinpthread-1.dll
81
112
cp -a " $BASEDIR " /enterprise/libcfenterprise/cf.events.x86_64.dll " $P " /bin/cf.events.dll
82
113
;;
83
114
* )
84
- echo " Unknown architecture: $ARCH "
115
+ log_error " Unknown architecture: $ARCH "
85
116
exit 1
86
117
;;
87
118
esac
88
119
120
+ # Copy WiX source file for MSI generation
89
121
cp " $BASEDIR " /buildscripts/packaging/cfengine-nova/cfengine-nova.wxs " $P "
122
+
123
+ # Handle OpenSSL library naming differences between architectures
90
124
# OpenSSL libs have different names on x32 and x64 platforms:
91
125
# on 32-bit platforms: libcrypto_1_1.dll and libssl_1_1.dll
92
126
# on 64-bit platforms: libcrypto_1_1_x64.dll and libssl_1_1_x64.dll
@@ -97,46 +131,72 @@ pre() {
97
131
fi
98
132
}
99
133
134
+ # candle() - Compile WiX source file (.wxs) into WiX object file (.wixobj)
135
+ # Parameters:
136
+ # $1 - REVISION: The version number for the MSI package
137
+ # Defines preprocessor variables for the WiX compilation:
138
+ # CfSourceDir: Current directory containing files to package
139
+ # CfVersion: Version number for the package
140
+ # CfArch: Architecture (x86 or x64)
100
141
candle () {
101
142
REVISION=" $1 "
143
+ log_debug " Running candle with REVISION=$REVISION , ARCH=$ARCH "
102
144
$CANDLE -dCfSourceDir=. -dCfVersion=" $REVISION " -dCfArch=" $ARCH " cfengine-nova.wxs
103
145
}
104
146
147
+ # light() - Link WiX object file into final MSI package
148
+ # Uses WiX linker to create the MSI from compiled object file
149
+ # Options:
150
+ # -sval: Suppress validation (speeds up build)
151
+ # -sice:ICE20: Suppress ICE20 validation (makes sure you have the necessary dialogs defined to handle things like showing a friendly message when the user cancels the install)
152
+ # -ext WixUtilExtension: Include WiX utility extension for additional functionality
105
153
light () {
154
+ log_debug " Running light to link WiX object into MSI"
106
155
$LIGHT -sval -sice:ICE20 -ext WixUtilExtension cfengine-nova.wixobj
107
156
}
108
157
158
+ # package() - Main packaging function that creates the MSI installer
109
159
package () {
160
+ log_debug " Creating MSI installer"
110
161
cd " $P "
111
162
163
+ # Determine the package revision number based on build configuration
164
+ log_debug " Determining package revision (BUILD_TYPE=$BUILD_TYPE , VERSION=$VERSION )"
112
165
if [ -z " $EXPLICIT_VERSION " ]; then
113
- # First make sure VERSION does not contain a 4th dot, since on windows we'll
166
+ # First make sure VERSION does not contain a 4th dot, since on Windows we'll
114
167
# add one later (plus they can only be numeric); so convert
115
168
# 3.10.0a.abcdef to 3.10.0a.
116
169
VERSION=$( echo " $VERSION " | sed -e ' s/\([^.]*\.[^.]*\.[^.]*\).*/\1/' )
117
170
118
171
case $BUILD_TYPE in
119
172
RELEASE)
173
+ # For release builds, use VERSION.RELEASE or VERSION.1
120
174
if [ -z " $EXPLICIT_RELEASE " ]; then
121
175
REVISION=" $VERSION .1"
122
176
else
123
177
REVISION=" $VERSION .$EXPLICIT_RELEASE "
124
178
fi
125
179
;;
126
180
DEBUG | CODE_COVERAGE)
181
+ # For debug/coverage builds, use main version with build number
182
+ # Strip anything after ~ (e.g., 3.10.0~build1 becomes 3.10.0)
127
183
MAIN_VERSION=${VERSION% \~ * }
128
184
REVISION=$MAIN_VERSION .$BUILD_NUMBER
129
185
;;
130
186
esac
131
187
else
188
+ # Use explicitly provided version with release number
132
189
if [ -z " $EXPLICIT_RELEASE " ]; then
133
190
REVISION=" $EXPLICIT_VERSION .1"
134
191
else
135
192
REVISION=" $EXPLICIT_VERSION .$EXPLICIT_RELEASE "
136
193
fi
137
194
fi
138
195
139
- # convert any alphabets in revison to int as no alphabets are allowed in windows package version
196
+ # Convert alphabetic characters to numeric
197
+ # MSI version numbers must be purely numeric
198
+ # Example: 3.10.0a becomes 3.10.097 (where 'a' = ASCII 97)
199
+ log_debug " Transforming $REVISION to only numeric characters by replacing alphabet characters to their ASCII value"
140
200
while true ; do
141
201
alphabet=$( echo " $REVISION " | sed -e ' s/[^a-zA-Z]*\([a-zA-Z]*\).*/\1/' )
142
202
if [ -n " $alphabet " ]; then
@@ -147,24 +207,28 @@ package() {
147
207
fi
148
208
done
149
209
150
- # ensure all revision components are 4 digits max (MSI allows each part to be up to 65534, but we limit it to 9999)
210
+ # Ensure each version component is max 4 digits
211
+ # MSI allows up to 65534 per component, but we limit to 9999 for simplicity
151
212
REVISION=$( echo " $REVISION " | tr ' .' ' \n' | sed ' s/\(....\).*/\1/' | tr ' \n' ' .' | sed ' s/\.$//' )
152
213
153
- # ensure revision has exactly 4 components - add .0.0.0 at the end and cut unneded parts
214
+ # MSI requires exactly 4 version components (Major.Minor.Build.Revision)
215
+ # Pad with zeros if needed, then truncate to exactly 4 components
154
216
REVISION=$( echo " $REVISION " .0.0.0 | cut -d ' .' -f 1-4)
155
217
156
- # Wix tools have a ridiculously short maximum file length of 128 characters.
157
- # This is easily exceeded when Jenkins workspace paths are involved. Luckily
158
- # we can shortcut the paths by using Windows drive letters to point to a
159
- # directory closer to the source files. Wine will automatically use the
160
- # shortest one.
218
+ # Work around WiX's 128-character path length limitation
219
+ # Long Jenkins workspace paths often exceed this limit
220
+ # Solution: Create a Wine drive letter symlink to current directory
221
+ # This provides a shorter path like D:\ instead of /home/user/very/long/path
161
222
162
- # Find a free drive letter. Z: is usually / in Wine, but apart from that it's
163
- # more likely to find free letters at the bottom end, so count backwards.
223
+ # Find an available drive letter for Wine mapping
224
+ # Start from Y: and work backwards (Z: is typically mapped to root /)
225
+ log_debug " Finding available Wine drive letter for path limitation workaround"
164
226
WORKSPACE_DRIVE=
165
227
for letter in y x w v u t s r q p o n m l k j i h g f e d; do
166
228
if [ ! -e " $HOME " /.wine/dosdevices/$letter : ]; then
167
229
WORKSPACE_DRIVE=$letter :
230
+ log_debug " Using Wine drive letter $WORKSPACE_DRIVE mapped to $PWD "
231
+ # Create symlink from Wine drive letter to current directory
168
232
ln -s " $PWD " " $HOME " /.wine/dosdevices/$WORKSPACE_DRIVE
169
233
break
170
234
fi
@@ -175,43 +239,58 @@ package() {
175
239
exit 2
176
240
fi
177
241
242
+ # Run WiX compilation and linking steps
243
+ log_debug " Starting WiX compilation and linking with final REVISION=$REVISION "
178
244
ret=0
179
245
candle " $REVISION " && light || ret=$?
180
246
181
- # Make sure the drive letter from above is cleaned up in case this build slave
182
- # is reused.
247
+ # Clean up Wine drive letter mapping to prevent conflicts in future builds
183
248
rm -f " $HOME " /.wine/dosdevices/$WORKSPACE_DRIVE
184
249
185
250
return $ret
186
251
}
187
252
253
+ # post() - Post-processing function to finalize the MSI package
254
+ # Moves the generated MSI to the output directory and renames it appropriately
188
255
post () {
256
+ log_debug " Finalizing MSI package"
257
+ # Create output directory and move the MSI file there
189
258
mkdir -p " $BASEDIR " /cfengine-nova
190
259
mv " $P " /cfengine-nova.msi " $BASEDIR " /cfengine-nova
191
260
cd " $BASEDIR " /cfengine-nova
192
261
193
- # For some reason candle is giving file no permissions at all.
262
+ # Fix file permissions - WiX/Wine sometimes creates files with no permissions
194
263
chmod 644 cfengine-nova.msi
195
264
265
+ # Determine package name based on build type
196
266
case $BUILD_TYPE in
197
267
RELEASE)
268
+ # Release builds: cfengine-nova-VERSION-RELEASE
198
269
PKGNAME=" cfengine-nova-$VERSION -${EXPLICIT_RELEASE:- 1} "
199
270
;;
200
271
DEBUG | CODE_COVERAGE)
272
+ # Debug/coverage builds: cfengine-nova-VERSION-BUILD_NUMBER
201
273
PKGNAME=" cfengine-nova-$VERSION -$BUILD_NUMBER "
202
274
;;
203
275
esac
204
276
277
+ # Rename MSI file with architecture suffix
278
+ log_debug " Renaming MSI file for architecture $ARCH with PKGNAME=$PKGNAME "
205
279
case $ARCH in
206
280
x86)
281
+ # 32-bit: Add i686 suffix
207
282
mv cfengine-nova.msi " $PKGNAME -i686.msi"
208
283
;;
209
284
x64)
285
+ # 64-bit: Add x86_64 suffix
210
286
mv cfengine-nova.msi " $PKGNAME -x86_64.msi"
211
287
;;
212
288
esac
213
289
}
214
290
215
- pre
216
- package
217
- post
291
+ # Main execution flow:
292
+ log_debug " --- Starting MSI package build process ---"
293
+ pre # Prepare packaging directory and copy files
294
+ package # Build the MSI using WiX tools
295
+ post # Finalize and rename the MSI package
296
+ log_debug " --- MSI package build completed ----"
0 commit comments