Skip to content

Commit 3ac8f05

Browse files
Merge pull request #23 from mbeddr/refactor/dmg-signing
Code signing of apps for macOS enabled
2 parents e1e83bd + 0284181 commit 3ac8f05

File tree

3 files changed

+77
-23
lines changed

3 files changed

+77
-23
lines changed

README.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ task buildDmg(type: de.itemis.mps.gradle.CreateDmg) {
4141
4242
backgroundImage file('path/to/background.png')
4343
dmgFile file('output.dmg')
44+
45+
signKeyChain file("/path/to/my.keychain-db")
46+
47+
signKeyChainPassword "my.keychain-db-password"
48+
49+
signIdentity "my Application ID Name"
4450
}
4551
```
4652

@@ -52,13 +58,17 @@ Parameters:
5258
* `backgroundImage` - the path to the background image.
5359
* `dmgFile` - the path and file name of the output DMG image. Must end
5460
with `.dmg`.
61+
* `signKeyChain (optional)` - the path and file name of the keychain which contains a code signing certificate.
62+
* `signKeyChainPassword (optional)` - the password which should be use to unlock the keychain.
63+
* `signIdentity (optional)` - the application ID of the code signing certificate.
5564

5665
### Operation
5766

5867
The task unpacks `rcpArtifact` into a temporary directory, unpacks
5968
the JDK given by `jdkDependency`/`jdk` under the `jre` subdirectory of
6069
the unpacked RCP artifact, fixes file permissions and creates missing
61-
symlinks, then creates a DMG image and configures its layout, using the
70+
symlinks. If the additional properties for code signing (`signKeyChain`, `signKeyChainPassword`, `signIdentity`) are defined,
71+
the application will be signed with the given certificate. Afterwards a DMG image is created and its layout is configured using the
6272
background image. Finally, the DMG is copied to `dmgFile`.
6373

6474
## BundleMacosJdk

src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy

+23-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.gradle.api.artifacts.Dependency
66
import org.gradle.api.tasks.InputFile
77
import org.gradle.api.tasks.OutputFile
88
import org.gradle.api.tasks.TaskAction
9+
import org.gradle.api.tasks.Optional
910

1011
class CreateDmg extends DefaultTask {
1112
@InputFile
@@ -20,6 +21,19 @@ class CreateDmg extends DefaultTask {
2021
@OutputFile
2122
File dmgFile
2223

24+
@Optional
25+
String signKeyChainPassword
26+
27+
@Optional
28+
String signIdentity
29+
30+
@InputFile @Optional
31+
File signKeyChain
32+
33+
def setSignKeyChain(Object file) {
34+
this.signKeyChain = project.file(file)
35+
}
36+
2337
def setRcpArtifact(Object file) {
2438
this.rcpArtifact = project.file(file)
2539
}
@@ -59,11 +73,19 @@ class CreateDmg extends DefaultTask {
5973
'Mac/Finder/DSStore/BuddyAllocator.pm', 'Mac/Finder/DSStore.pm']
6074
File scriptsDir = File.createTempDir()
6175
File dmgDir = File.createTempDir()
76+
def signingInfo = [signKeyChainPassword, signKeyChain, signIdentity]
6277
try {
6378
BundledScripts.extractScriptsToDir(scriptsDir, scripts)
6479
project.exec {
6580
executable new File(scriptsDir, 'mpssign.sh')
66-
args rcpArtifact, dmgDir, jdk
81+
82+
if(signingInfo.every {it != null}) {
83+
args '-r', rcpArtifact, '-o', dmgDir, '-j', jdk, '-p', signKeyChainPassword, '-k', signKeyChain, '-i', signIdentity
84+
}else if (signingInfo.every {it == null}){
85+
args '-r', rcpArtifact, '-o', dmgDir, '-j', jdk
86+
}else{
87+
throw new IllegalArgumentException("Not all signing paramters set. signKeyChain: ${getSigningInfo[1]}, signIdentity: ${getSigningInfo[2]} and signKeyChainPassword needs to be set. ")
88+
}
6789
workingDir scriptsDir
6890
}
6991
project.exec {

src/main/resources/de/itemis/mps/gradle/mpssign.sh

+43-21
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,42 @@
11
#!/bin/bash
2-
if [[ $# -ne 3 && $# -ne 2 ]]; then
3-
cat <<EOF
4-
Usage:
2+
USAGE="Usage:
53
6-
$0 RCP_FILE OUTPUT_DIR [JDK_FILE]
4+
$0 -r <rcp_file> -o <output_dir> [-j <jdk_file>] [-p <password keychain> -k <keychain> -i <sign identity>]
75
86
1. Extracts RCP_FILE into OUTPUT_DIR
97
2. Creates symlinks Contents/bin/*.dylib -> *.jnilib
10-
3. If JDK_FILE is given, extracts JDK_FILE under Contents/jre/
8+
3. If JDK_FILE is given extracts JDK_FILE under Contents/jre/
119
4. Builds help indices using hiutil if help is present under Contents/Resources/
1210
5. Sets executable permissions on Contents/MacOS/* and appropriate Contents/bin/ files
13-
11+
6. If given, signs the application with the passed SIGN_PW, SIGN_KEY_CHAIN and SIGN_IDENTITY
1412
IMPORTANT: All arguments must use absolute paths because the script changes the current directory several times!
15-
EOF
16-
exit 1
17-
fi
18-
13+
"
1914
set -o errexit # Exit immediately on any error
2015

21-
# Arguments
22-
RCP_FILE="$1"
23-
OUTPUT_DIR="$2"
24-
JDK_FILE="$3"
16+
# Parse arguments
17+
while getopts ":r:o:j:p:k:i:h" option;
18+
do
19+
case "${option}" in
20+
r) RCP_FILE="$OPTARG";;
21+
o) OUTPUT_DIR="$OPTARG";;
22+
j) JDK_FILE="$OPTARG";;
23+
p) SIGN_PW="$OPTARG";;
24+
k) SIGN_KEY_CHAIN="$OPTARG";;
25+
i) SIGN_IDENTITY="$OPTARG";;
26+
h) echo "$USAGE"
27+
exit 0;;
28+
\?) echo "illegal option: -$OPTARG usage: $0 -r <rcp_file> -o <output_dir> [-j <jdk_file>] [-p <password keychain> -k <keychain> -i <sign identity>]" >&2
29+
exit 1;;
30+
:) echo "option: -$OPTARG requires an argument" >&2
31+
exit 1;;
32+
esac
33+
done
34+
shift $((OPTIND -1)) #remove options that have already been handled from $@
35+
36+
if [[ -z "$RCP_FILE" || -z "$OUTPUT_DIR" ]]; then
37+
echo "$USAGE"
38+
exit 1
39+
fi
2540

2641
echo "Unzipping $RCP_FILE to $OUTPUT_DIR..."
2742
unzip -q -o "$RCP_FILE" -d "$OUTPUT_DIR"
@@ -71,13 +86,20 @@ if [[ -d "$HELP_DIR" ]]; then
7186
hiutil -Cagvf "$HELP_DIR/search.helpindex" "$HELP_DIR"
7287
fi
7388

74-
# Make sure JetBrainsMacApplication.p12 is imported into local KeyChain
75-
#security unlock-keychain -p <password> /Users/builduser/Library/Keychains/login.keychain
76-
#codesign -v --deep -s "Developer ID Application: JetBrains" "$OUTPUT_DIR/$BUILD_NAME"
77-
#echo "signing is done"
78-
#echo "check sign"
79-
#codesign -v "$OUTPUT_DIR/$BUILD_NAME" -vvvvv
80-
#echo "check sign done"
89+
# Make sure your certificate is imported into local KeyChain
90+
if [[ -n "$SIGN_PW" && -n "$SIGN_KEY_CHAIN" && -n "$SIGN_IDENTITY" ]]; then
91+
echo "Signing application $BUILD_NAME"
92+
echo "key chain: $SIGN_KEY_CHAIN"
93+
echo "sign identity: $SIGN_IDENTITY"
94+
security unlock-keychain -p $SIGN_PW $SIGN_KEY_CHAIN
95+
codesign -v --deep -s "$SIGN_IDENTITY" "$OUTPUT_DIR/$BUILD_NAME"
96+
echo "signing is done"
97+
echo "check sign"
98+
codesign -v "$OUTPUT_DIR/$BUILD_NAME" -vvvvv
99+
echo "check sign done"
100+
else
101+
echo "for signing the application $BUILD_NAME: SIGN_PW, SIGN_KEY_CHAIN and SIGN_IDENTITY needs to be provided"
102+
fi
81103

82104
chmod a+x "$CONTENTS"/MacOS/*
83105
chmod a+x "$CONTENTS"/bin/*.py

0 commit comments

Comments
 (0)