-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathsimple_launchdaemon_creator.sh
executable file
·146 lines (125 loc) · 5.55 KB
/
simple_launchdaemon_creator.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/bash
identifier="" # com.company.package
packageName="" # Package
version="" # 1.0
target="" # main_script_name.sh
# Prompt for the identifier, strip off .plist if it is included
[[ -z "$identifier" ]] && identifier=$(osascript -e 'set identifier to the text returned of (display dialog "Enter the identifier of the package." default answer "com.company.package")' 2> /dev/null)
[[ -z "$identifier" ]] && echo "User cancelled; exiting" && exit 0
identifier=${identifier%.plist*}
echo "Identifier set to: $identifier"
# Prompt for the name of the package, strip off .pkg if it is included
[[ -z "$packageName" ]] && packageName=$(osascript -e 'set packageName to the text returned of (display dialog "Enter the name of the package." default answer "Package Name")' 2> /dev/null)
[[ -z "$packageName" ]] && echo "User cancelled; exiting" && exit 0
packageName=${packageName%.pkg*}
echo "Package Name set to: $packageName"
# Prompt for the version
[[ -z "$version" ]] && version=$(osascript -e 'set theVersion to the text returned of (display dialog "Enter the version of the package." default answer "1.0")' 2> /dev/null)
[[ -z "$version" ]] && echo "User cancelled; exiting" && exit 0
echo "Version set to: $version"
# Prompt for the target of the LaunchDaemon
[[ -z "$target" ]] && target=$(osascript -e 'set new_file to POSIX path of (choose file with prompt "Choose target sh script or app." of type {"SH","BASH","PY","APP"})' 2> /dev/null)
[[ -z "$target" ]] && echo "User cancelled; exiting." && exit 0
targetPath=${target%/}
targetName=${targetPath##*/}
echo "Target Name is: $targetName"
# Configure the target and warn if .app is chosen
if [[ "$targetName" == *.app ]]; then
echo "Warning user of LaunchDaemon use to open applications."
[[ -z "$confirmation" ]] && confirmation=$(osascript -e 'display dialog "Opening an app that requires a GUI is better suited for a LaunchAgent. Are you sure you want to continue?" buttons {"Cancel","I Understand"} default button 2 with icon 2' 2> /dev/null)
[[ -z "$confirmation" ]] && echo "User cancelled; exiting." && exit 0
echo "Setting LaunchDaemon program arguments to open an app..."
programArguments="/usr/bin/open"
else
echo "Setting LaunchDaemon program arguments to run a script..."
# Try to determine the program arguments from the script's shebang
case "$(head -n 1 "$targetPath")" in
*bash)
programArguments="/bin/bash"
;;
*sh)
programArguments="/bin/sh"
;;
*python)
programArguments="/usr/bin/python"
;;
esac
fi
echo "Program Arguments set to: $programArguments"
# Create/clean our build directories
echo "Build directory will be: /private/tmp/$packageName"
find "/private/tmp/$packageName" -mindepth 1 -delete
mkdir -p "/private/tmp/$packageName/files/Library/LaunchDaemons"
mkdir -p "/private/tmp/$packageName/files/Library/Scripts/"
mkdir -p "/private/tmp/$packageName/scripts"
mkdir -p "/private/tmp/$packageName/build"
# Move target into place
echo "Moving $targetName to temporary build directory..."
cp -R "$targetPath" "/private/tmp/$packageName/files/Library/Scripts/"
# Create the LaunchDaemon plist
echo "Creating the LaunchDaemon plist..."
cat << EOF > "/private/tmp/$packageName/files/Library/LaunchDaemons/$identifier.plist"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>$identifier</string>
<key>ProgramArguments</key>
<array>
<string>$programArguments</string>
<string>/Library/Scripts/$targetName</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/Library/Logs/$identifier.log</string>
<key>StandardOutPath</key>
<string>/Library/Logs/$identifier.log</string>
</dict>
</plist>
EOF
# Create the preinstall script
echo "Creating the preinstall/postinstall scripts..."
cat << EOF > "/private/tmp/$packageName/scripts/preinstall"
#!/bin/bash
# Stop our LaunchDaemon
/bin/launchctl unload -w /Library/LaunchDaemons/$identifier.plist
exit 0
EOF
# Create the postinstall script
cat << EOF > "/private/tmp/$packageName/scripts/postinstall"
#!/bin/bash
# Set permissions on LaunchDaemon and Script
chown root:wheel /Library/LaunchDaemons/$identifier.plist
chmod 644 /Library/LaunchDaemons/$identifier.plist
chown -R root:wheel "/Library/Scripts/$targetName"
chmod -R 755 "/Library/Scripts/$targetName"
# Start our LaunchDaemon
/bin/launchctl load -w /Library/LaunchDaemons/$identifier.plist
exit 0
EOF
# Set permission on the preinstall/postinstall scripts
chmod +x "/private/tmp/$packageName/scripts/postinstall"
chmod +x "/private/tmp/$packageName/scripts/preinstall"
# Remove any unwanted .DS_Store files from the temp build directory
find "/private/tmp/$packageName/" -name '*.DS_Store' -type f -delete
# Remove any extended attributes (ACEs) from the temp build directory
/usr/bin/xattr -rc "/private/tmp/$packageName"
# Build the .pkg
echo "Building the .pkg in: /private/tmp/$packageName/build/"
/usr/bin/pkgbuild --quiet --root "/private/tmp/$packageName/files/" \
--install-location "/" \
--scripts "/private/tmp/$packageName/scripts/" \
--identifier "$identifier" \
--version "$version" \
--ownership recommended \
"/private/tmp/$packageName/build/${packageName}_${version}.pkg"
# shellcheck disable=SC2181
if [[ "$?" == "0" ]]; then
echo "Revealing ${packageName}_${version}.pkg in Finder"
open -R "/private/tmp/$packageName/build/${packageName}_${version}.pkg"
else
echo "Build failed."
fi
exit 0