-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new launcher script and luggage package components
- New launcher script, coordinated by LaunchAgents and LaunchDaemons, handles delivering the notification in the console user's context even if there is no console user (i.e. an admin tool is requesting the notification).
- Loading branch information
1 parent
1d29b92
commit 336ee90
Showing
9 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.pyc | ||
*.app | ||
*.pkg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
include /usr/local/share/luggage/luggage.make | ||
|
||
TITLE=yo | ||
REVERSE_DOMAIN=com.sheagcraig | ||
PAYLOAD=\ | ||
pack-utilities-yo.app \ | ||
pack-usr-local-bin-yo.py \ | ||
pack-Library-LaunchAgents-com.sheagcraig.yo.on_demand.plist \ | ||
pack-Library-LaunchAgents-com.sheagcraig.yo.login_once.plist \ | ||
pack-Library-LaunchDaemons-com.sheagcraig.yo.cleanup.plist \ | ||
pack-script-postinstall \ | ||
pack-script-preinstall \ | ||
|
||
PACKAGE_VERSION=$(shell defaults read "$(PWD)/yo.app/Contents/Info.plist" CFBundleShortVersionString) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?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>com.sheagcraig.yo.cleanup</string> | ||
<key>ProgramArguments</key> | ||
<array> | ||
<string>/usr/local/bin/yo</string> | ||
<string>--cleanup</string> | ||
</array> | ||
<key>KeepAlive</key> | ||
<dict> | ||
<key>PathState</key> | ||
<dict> | ||
<key>/private/tmp/.com.sheagcraig.yo.cleanup.launchd</key> | ||
<true/> | ||
</dict> | ||
</dict> | ||
<key>OnDemand</key> | ||
<true/> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?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>com.sheagcraig.yo.login_once</string> | ||
<key>LimitLoadToSessionType</key> | ||
<array> | ||
<string>Aqua</string> | ||
</array> | ||
<key>ProgramArguments</key> | ||
<array> | ||
<string>/usr/local/bin/yo</string> | ||
<string>--cached</string> | ||
</array> | ||
<key>RunAtLoad</key> | ||
<true/> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?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>com.sheagcraig.yo.on_demand</string> | ||
<key>LimitLoadToSessionType</key> | ||
<array> | ||
<string>Aqua</string> | ||
</array> | ||
<key>ProgramArguments</key> | ||
<array> | ||
<string>/usr/local/bin/yo</string> | ||
<string>--cached</string> | ||
</array> | ||
<key>KeepAlive</key> | ||
<dict> | ||
<key>PathState</key> | ||
<dict> | ||
<key>/private/tmp/.com.sheagcraig.yo.on_demand.launchd</key> | ||
<true/> | ||
</dict> | ||
</dict> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/bin/bash | ||
|
||
# Rename yo.sh to yo so we can call it like a regular cli utility. | ||
mv /usr/local/bin/yo.py /usr/local/bin/yo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/bin/bash | ||
|
||
# Weirdly, yo doesn't overwrite it's old app; instead it makes a | ||
# localized folder. Just erase it first. | ||
rm -rf /Applications/Utilities/yo.app | ||
rm -rf /Applications/Utilities/yo | ||
rm -rf /Applications/Utilities/yo.localized |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
#!/usr/bin/python | ||
|
||
|
||
import argparse | ||
import os | ||
from subprocess import call | ||
import sys | ||
import time | ||
|
||
from Foundation import (CFPreferencesAppSynchronize, CFPreferencesCopyAppValue, | ||
CFPreferencesSetValue, kCFPreferencesAnyUser, | ||
kCFPreferencesCurrentHost) | ||
from SystemConfiguration import SCDynamicStoreCopyConsoleUser | ||
|
||
__version__ == 2.0.0 | ||
BUNDLE_ID = "com.sheagcraig.yo" | ||
CLEANUP_PATH = "/private/tmp/.com.sheagcraig.yo.cleanup.launchd" | ||
WATCH_PATH = "/private/tmp/.com.sheagcraig.yo.on_demand.launchd" | ||
YO_BINARY = "/Applications/Utilities/yo.app/Contents/MacOS/yo" | ||
YO_HELP = """\ | ||
Yo app notification options: | ||
-t, --title: | ||
Title for notification. REQUIRED. | ||
-s, --subtitle: | ||
Subtitle for notification. | ||
-n, --info: | ||
Informative text. | ||
-b, --action-btn: | ||
Include an action button, with the button label text supplied to this | ||
argument. | ||
-a, --action-path: | ||
Application to open if user selects the action button. Provide the full | ||
path as the argument. This option only does something if | ||
-b/--action-btn is also specified. | ||
-B, --bash-action: | ||
Bash script to run. Be sure to properly escape all reserved characters. | ||
This option only does something if -b/--action-btn is also specified. | ||
Defaults to opening nothing. | ||
-o, --other-btn: | ||
Alternate label for cancel button text. | ||
-i, --icon: | ||
Complete path to an alternate icon to use for the notification. | ||
-c, --content-image: | ||
Path to an image to use for the notification's 'contentImage' property. | ||
-z, --delivery-sound: | ||
The name of the sound to play when delivering or 'None'. The name must | ||
not include the extension, nor any path components, and should be | ||
located in '/Library/Sounds' or '~/Library/Sounds'. (Defaults to the | ||
system's default notification sound). See the README for more info. | ||
-d, --ignores-do-not-disturb: | ||
Set to make your notification appear even if computer is in | ||
do-not-disturb mode. | ||
-l, --lockscreen-only: | ||
Set to make your notification appear only if computer is locked. If | ||
set, no buttons will be available. | ||
-p, --poofs-on-cancel: | ||
Set to make your notification 'poof' when the cancel button is hit. | ||
-m, --banner-mode: | ||
Does not work! Set if you would like to send a non-persistent | ||
notification. No buttons will be available if set. | ||
-v, --version: | ||
Display Yo version information.""" | ||
|
||
|
||
def main(): | ||
# Capture commandline args. | ||
parser = get_argument_parser() | ||
launcher_args, yo_args = parser.parse_known_args() | ||
|
||
# args = sys.argv | ||
# Replace this script's path with the yo app's path. | ||
# args[0] = "/Applications/Utilities/yo.app/Contents/MacOS/yo" | ||
|
||
if any(flag in yo_args for flag in ("--version", "-v")): | ||
# import pdb; pdb.set_trace() | ||
# Skip further checks if version is requested. | ||
args = ["yo.py"] + yo_args | ||
run_yo_with_args(args) | ||
|
||
elif launcher_args.cached: | ||
# Yo is being run by a LaunchAgent for the current console user. | ||
cached_args = get_cached_args() | ||
all_args = cached_args + [yo_args] | ||
|
||
# Post all of the stored notifications! | ||
for arg_set in all_args: | ||
run_yo_with_args(arg_set) | ||
|
||
# Trigger the LaunchDaemon to clean up. | ||
with open(CLEANUP_PATH, "w") as ofile: | ||
ofile.write("Yo!") | ||
|
||
elif launcher_args.cleanup: | ||
# Yo is being called by the cleanup LaunchDaemon. | ||
clear_args() | ||
|
||
elif not is_console_user() and os.getuid() == 0: | ||
# Only the current console user can trigger a notification. | ||
# So we will cache the required arguments and try to trigger | ||
# an on_demand notification. If there is no console user, the | ||
# notification will trigger on the next login. | ||
cache_args(yo_args) | ||
|
||
if get_console_user()[0]: | ||
with open(WATCH_PATH, "w") as ofile: | ||
ofile.write("Yo!") | ||
|
||
time.sleep(5) | ||
os.remove(WATCH_PATH) | ||
|
||
else: | ||
# Yo has been run by the current user directly | ||
# Non-root users cannot get the cached notifications, so just | ||
# run the one provided on the commandline. | ||
run_yo_with_args(yo_args) | ||
|
||
|
||
def get_argument_parser(): | ||
"""Create our argument parser.""" | ||
description = "Yo launcher arguments:" | ||
parser = argparse.ArgumentParser( | ||
description=description, | ||
formatter_class=argparse.RawDescriptionHelpFormatter) | ||
phelp = ("Run cached notifications (must be run as console user). This " | ||
"option is normally run") | ||
parser.add_argument("--cached", help=argparse.SUPPRESS, action="store_true") | ||
phelp = "Clean up cached notifications (must run as root)." | ||
parser.add_argument("--cleanup", help=argparse.SUPPRESS, action="store_true") | ||
|
||
parser.epilog = YO_HELP | ||
|
||
return parser | ||
|
||
|
||
def run_yo_with_args(args): | ||
args = [YO_BINARY] + args | ||
call(args) | ||
|
||
|
||
def is_console_user(): | ||
return os.getuid() == get_console_user()[1] | ||
|
||
|
||
def get_console_user(): | ||
return SCDynamicStoreCopyConsoleUser(None, None, None) | ||
|
||
|
||
def get_cached_args(): | ||
notifications = CFPreferencesCopyAppValue("Notifications", BUNDLE_ID) | ||
return notifications or [] | ||
|
||
|
||
def cache_args(args): | ||
notifications = CFPreferencesCopyAppValue("Notifications", BUNDLE_ID) | ||
if not notifications: | ||
notifications = [] | ||
|
||
notifications = notifications + [args] | ||
|
||
CFPreferencesSetValue("Notifications", notifications, BUNDLE_ID, | ||
kCFPreferencesAnyUser, kCFPreferencesCurrentHost) | ||
CFPreferencesAppSynchronize(BUNDLE_ID) | ||
|
||
|
||
def clear_args(): | ||
CFPreferencesSetValue("Notifications", [], BUNDLE_ID, | ||
kCFPreferencesAnyUser, kCFPreferencesCurrentHost) | ||
CFPreferencesAppSynchronize(BUNDLE_ID) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |