-
-
Save arubdesu/8271ba29ac5aff8f982c to your computer and use it in GitHub Desktop.
refactor with slightly more error handling, potential for logging any called-scripts stdout/stderr(s) to syslog
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
#!/usr/bin/python | |
# scriptRunner will run all scripts within a folder that you specify. | |
# Useful for LaunchAgents and running multiple scripts at user login. | |
# Thanks to Greg Neagle for an example of how to do this and Nate Walck for v1 | |
# Copyright 2014 Allister Banks (see end for Apache license blurb) | |
import optparse | |
import os | |
import subprocess | |
import plistlib | |
import datetime | |
import sys | |
import stat | |
import logging | |
import logging.handlers | |
# Set your organizations reverse domain in the 'once' check file: | |
orgPlistString = "org.my.scriptRunnerOnce.plist" | |
# logging.basicConfig(level=logging.WARN) | |
# logr = logging.getLogger('scriptRunner') | |
# handler = logging.handlers.SysLogHandler(address = '/private/var/run/syslog') | |
# logr.addHandler(handler) | |
## Possible ways to get called command output to syslog: | |
# def sh(cmd): | |
# return Popen(cmd,shell=True,stdout=PIPE,stderr=PIPE).communicate()[0] | |
# output = (sh("/usr/local/sbin/mgmt/everyTest.sh")) | |
# # logr.critical(sh('echo "foo"')) | |
# logr.critical("SCRIPTRUNNER: %s", output) | |
# TODO: - check return code from called script | |
# - send stderr/out to (sys)log | |
# Further: | |
# - default wrap shell scripts with 'bash -x'? 'once' only? | |
# - separate, permanent log(s) for called script/scriptRunner itself? | |
# (issue is launchA can't write to /var/log, & /Users/Shared or /tmp aren't ideal) | |
# maybe setup tee'd output to ~/Lib/Logs when subprocess calls? | |
def checkPermsAndRun(script): | |
st = os.stat(script) | |
mode = st.st_mode | |
if script.lower().endswith(('.rb', '.py', '.sh')): | |
# only run if executable AND everyone write access is NOT set | |
# as explained succinctly here: http://stackoverflow.com/a/1861970 | |
if (mode & stat.S_IXOTH) and not (mode & stat.S_IWOTH): | |
subprocess.call(script, shell=True) | |
else: | |
print script + " is not executable or has bad permissions" | |
def main(): | |
p = optparse.OptionParser() | |
p.set_usage("""Usage: %prog [options]""") | |
p.add_option('--once', '-o', dest='runOnce', | |
help="""Directory of scripts to run only once.""") | |
p.add_option('--every', '-e', dest='runEvery', | |
help="""Directory of scripts to run every time.""") | |
options, arguments = p.parse_args() | |
if not (options.runOnce or options.runEvery): | |
print "Please choose a frequency and the path to a folder containing (1 or more) scripts" | |
p.print_help() | |
sys.exit(1) | |
# Check to see if passed options are a directory that exists or not | |
for path in (options.runOnce, options.runEvery): | |
if path is not None: | |
if not os.path.isdir(path): | |
sys.exit(path + " is not a directory") | |
if options.runEvery: | |
for script in os.listdir(options.runEvery): | |
checkPermsAndRun(os.path.join(options.runEvery, script)) | |
if options.runOnce: | |
runOncePlist = os.path.expanduser("~/Library/Preferences/") + orgPlistString | |
try: | |
runOncePlistValues = plistlib.readPlist(runOncePlist) | |
except IOError: | |
runOncePlistValues = {} | |
for script in os.listdir(options.runOnce): | |
if script in runOncePlistValues: | |
print os.path.join(options.runOnce, script) + " already run!" | |
else: | |
checkPermsAndRun(os.path.join(options.runOnce, script)) | |
runOncePlistValues[script] = datetime.datetime.now() | |
plistlib.writePlist(runOncePlistValues, runOncePlist) | |
if __name__ == '__main__': | |
main() | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment