Commits

Anonymous committed 82af551

Clean up behaviour when starting and stopping and refactor version number.

Invoking nosier with no args produces the help text instead of a
trace back.

Keyboard interrupt now cleanly exits without a trace back.

Version number factored out to constants file which setup.py can get
access to without importing inotifyx (causes install failure).

Comments (0)

Files changed (4)

nosier/__init__.py

-from nosier import *

nosier/constants.py

+USAGE = '''\
+Usage: %prog [options] command
+
+Monitor directories and files for changes.  On detecting a change run
+the specified command.'''
+
+VERSION_NUMBER = '0.11'
+
+VERSION = '%%prog version %s' % VERSION_NUMBER
+
+BUILTIN_BLACK_LIST = ['.hg', '.git', '.bzr', '.svn', '#*', '.#*', '*.swp']
+
+WIDTH = 80
+from constants import *
+import inotifyx
 import subprocess
-import inotifyx
 import optparse
 import fnmatch
 import time
 import sys
 import os
 
-USAGE = '''\
-Usage: %prog [options] command
-
-Monitor directories and files for changes.  On detecting a change run
-the specified command.'''
-
-VERSION = '0.10'
-VERSION_TEXT = '%%prog version %s' % VERSION
-
 WATCH_EVENTS = inotifyx.IN_CREATE | inotifyx.IN_MODIFY | inotifyx.IN_DELETE | inotifyx.IN_DELETE_SELF | inotifyx.IN_MOVE
-BUILTIN_BLACK_LIST = ['.hg', '.git', '.bzr', '.svn', '#*', '.#*', '*.swp']
-WIDTH = 80
-
 
 def iteration_generator():
     i = 0
 
 
 def main():
-    # Process command line options.
-    parser = optparse.OptionParser(usage=USAGE, version=VERSION_TEXT)
-    parser.add_option('-p', '--path', action='append',
-                      help='add a path to monitor for changes, if no paths are specified then the current directory will be monitored')
-    parser.add_option('-d', '--delay', type='float', default=0.1,
-                      help='how long to wait for additional events after a command run is triggered, defaults to %default second')
-    parser.add_option('-i', '--ignore-events', action='store_true', default=False,
-                      help='whether to ignore events that occur during the command run, defaults to %default')
-    parser.add_option('-w', '--white-list', action='append', default=[], metavar='FILE',
-                      help='add a file to the white list, ensure globs are quoted to avoid shell expansion')
-    parser.add_option('-b', '--black-list', action='append', default=[], metavar='FILE',
-                      help='add a file to the black list, ensure globs are quoted to avoid shell expansion')
-    parser.add_option('-l', '--no-default-black-list', action='store_true', default=False,
-                      help='''don't add the following to the black list: %s''' % ' '.join(BUILTIN_BLACK_LIST))
-    parser.add_option('-r', '--no-initial-run', action='store_true', default=False,
-                      help='''don't perform an initial run of the command, instead start monitoring and wait for changes''')
+    try:
+        # Process command line options.
+        parser = optparse.OptionParser(usage=USAGE, version=VERSION)
+        parser.add_option('-p', '--path', action='append',
+                          help='add a path to monitor for changes, if no paths are specified then the current directory will be monitored')
+        parser.add_option('-d', '--delay', type='float', default=0.1,
+                          help='how long to wait for additional events after a command run is triggered, defaults to %default second')
+        parser.add_option('-i', '--ignore-events', action='store_true', default=False,
+                          help='whether to ignore events that occur during the command run, defaults to %default')
+        parser.add_option('-w', '--white-list', action='append', default=[], metavar='FILE',
+                          help='add a file to the white list, ensure globs are quoted to avoid shell expansion')
+        parser.add_option('-b', '--black-list', action='append', default=[], metavar='FILE',
+                          help='add a file to the black list, ensure globs are quoted to avoid shell expansion')
+        parser.add_option('-l', '--no-default-black-list', action='store_true', default=False,
+                          help='''don't add the following to the black list: %s''' % ' '.join(BUILTIN_BLACK_LIST))
+        parser.add_option('-r', '--no-initial-run', action='store_true', default=False,
+                          help='''don't perform an initial run of the command, instead start monitoring and wait for changes''')
 
-    options, command = parser.parse_args()
+        options, command = parser.parse_args()
 
-    paths = options.path or ['.']
-    delay = options.delay
-    ignore_events = options.ignore_events
-    white_list = options.white_list
-    black_list = options.black_list
-    if not options.no_default_black_list:
-        black_list.extend(BUILTIN_BLACK_LIST)
-    no_initial_run = options.no_initial_run
+        if not command:
+            parser.print_help()
+            return
 
-    # Fn that indicates if name is in or out.
-    def white_listed(name):
-        for pattern in white_list:
-            if fnmatch.fnmatch(name, pattern):
-                return True
-        for pattern in black_list:
-            if fnmatch.fnmatch(name, pattern):
-                return False
-        return True
+        paths = options.path or ['.']
+        delay = options.delay
+        ignore_events = options.ignore_events
+        white_list = options.white_list
+        black_list = options.black_list
+        if not options.no_default_black_list:
+            black_list.extend(BUILTIN_BLACK_LIST)
+        no_initial_run = options.no_initial_run
 
-    # Init inotify.
-    fd = inotifyx.init()
+        # Fn that indicates if name is in or out.
+        def white_listed(name):
+            for pattern in white_list:
+                if fnmatch.fnmatch(name, pattern):
+                    return True
+            for pattern in black_list:
+                if fnmatch.fnmatch(name, pattern):
+                    return False
+            return True
 
-    # Watch specified paths.
-    print 'Setting up watches on paths'
+        # Init inotify.
+        fd = inotifyx.init()
 
-    watches = {}
-    watches.update((inotifyx.add_watch(fd, path, WATCH_EVENTS), path)
-                   for path in paths)
+        # Watch specified paths.
+        print 'Setting up watches on paths'
 
-    # Watch sub dirs of specified paths.  Ensure we modify dirs in
-    # place so that os.walk only traverses white listed dirs.
-    for path in paths:
-        for root, dirs, files in os.walk(path):
-            dirs[:] = [dir for dir in dirs if white_listed(dir)]
-            watches.update((inotifyx.add_watch(fd, os.path.join(root, dir), WATCH_EVENTS), os.path.join(root, dir))
-                           for dir in dirs)
+        watches = {}
+        watches.update((inotifyx.add_watch(fd, path, WATCH_EVENTS), path)
+                       for path in paths)
 
-    print 'Watching %d paths' % len(watches)
+        # Watch sub dirs of specified paths.  Ensure we modify dirs in
+        # place so that os.walk only traverses white listed dirs.
+        for path in paths:
+            for root, dirs, files in os.walk(path):
+                dirs[:] = [dir for dir in dirs if white_listed(dir)]
+                watches.update((inotifyx.add_watch(fd, os.path.join(root, dir), WATCH_EVENTS), os.path.join(root, dir))
+                               for dir in dirs)
 
-    # Initial command run.
-    if not no_initial_run:
-        run_command(command, fd, watches, [], ignore_events, white_listed)
+        print 'Watching %d paths' % len(watches)
 
-    # Monitor and run the specified command until keyboard interrupt.
-    while True:
-        # Block until events arrive.
-        events = inotifyx.get_events(fd)
+        # Initial command run.
+        if not no_initial_run:
+            run_command(command, fd, watches, [], ignore_events, white_listed)
 
-        # Continue collecting events for the delay period.  This
-        # allows events that occur close to the trigger event to be
-        # collected now rather than causing another run immediately
-        # after this run.
-        end = time.time() + delay
-        while time.time() < end:
-            events.extend(inotifyx.get_events(fd, 0))
+        # Monitor and run the specified command until keyboard interrupt.
+        while True:
+            # Block until events arrive.
+            events = inotifyx.get_events(fd)
 
-        # Filter to events that have no name (self destruct watch
-        # events) and to events that have names that are considered
-        # white listed.
-        events = [event for event in events if not event.name or white_listed(event.name)]
+            # Continue collecting events for the delay period.  This
+            # allows events that occur close to the trigger event to be
+            # collected now rather than causing another run immediately
+            # after this run.
+            end = time.time() + delay
+            while time.time() < end:
+                events.extend(inotifyx.get_events(fd, 0))
 
-        # Track watched dirs.
-        for e in events:
-            if e.mask & inotifyx.IN_ISDIR and e.mask & inotifyx.IN_CREATE:
-                watches[inotifyx.add_watch(fd, os.path.join(watches.get(e.wd), e.name), WATCH_EVENTS)] = os.path.join(watches.get(e.wd), e.name)
-            elif e.mask & inotifyx.IN_DELETE_SELF:
-                watches.pop(e.wd, None)
+            # Filter to events that have no name (self destruct watch
+            # events) and to events that have names that are considered
+            # white listed.
+            events = [event for event in events if not event.name or white_listed(event.name)]
 
-        # Do command run provided we have events after white listing.
-        if events:
-            run_command(command, fd, watches, events, ignore_events, white_listed)
+            # Track watched dirs.
+            for e in events:
+                if e.mask & inotifyx.IN_ISDIR and e.mask & inotifyx.IN_CREATE:
+                    watches[inotifyx.add_watch(fd, os.path.join(watches.get(e.wd), e.name), WATCH_EVENTS)] = os.path.join(watches.get(e.wd), e.name)
+                elif e.mask & inotifyx.IN_DELETE_SELF:
+                    watches.pop(e.wd, None)
+
+            # Do command run provided we have events after white listing.
+            if events:
+                run_command(command, fd, watches, events, ignore_events, white_listed)
+
+    except KeyboardInterrupt:
+        # Exit requested so print blank line to ensure command prompt
+        # will be on a clean new line and exit.
+        print ''
+        pass
 
 
 if __name__ == '__main__':
+import nosier.constants
 import setuptools
 
 setuptools.setup(name='nosier',
-                 version='0.10',
+                 version=nosier.constants.VERSION_NUMBER,
                  description='Monitors paths for changes and then runs a specified command',
                  long_description=open('README').read().strip(),
                  author='Meme Dough',