Commits

Richo Healey committed 6897227

Have doko use strategies in order, configurably

This also should complete the changes needed to make it do reasonable
things on windows and linux

Comments (0)

Files changed (1)

 
 import sys
 import optparse
+from optparse import OptionValueError
 import time
 from collections import namedtuple
+from collections import OrderedDict
 import webbrowser
 
 try:
 DEFAULT_TIMEOUT = 3
 DEFAULT_RETRIES = 10
 
+LOCATION_STRATEGIES = OrderedDict()
+
+# Important, define strategies in default resolution order
+def location_strategy(name):
+    def _(fn):
+        LOCATION_STRATEGIES[name] = fn
+    return _
 
 class LocationServiceException(Exception):
     pass
 
 
-def location(timeout=DEFAULT_TIMEOUT):
-    """
-    Fetch and return a Location from OS X Core Location, or throw
-    a LocationServiceException trying.
-    """
-    if not CoreLocation:
-        raise LocationServiceException('CoreLocation not available')
-
-    m = CoreLocation.CLLocationManager.new()
-
-    if not m.locationServicesEnabled():
-        raise LocationServiceException(
-                'location services not enabled -- check privacy settings in System Preferences'  # noqa
-            )
+if CoreLocation:
+    @location_strategy("corelocation")
+    def corelocation_location(timeout=DEFAULT_TIMEOUT):
+        """
+        Fetch and return a Location from OS X Core Location, or throw
+        a LocationServiceException trying.
+        """
 
-    if not m.locationServicesAvailable():
-        raise LocationServiceException('location services not available')
+        m = CoreLocation.CLLocationManager.new()
 
-    m.startUpdatingLocation()
-    CoreLocation.CFRunLoopStop(CoreLocation.CFRunLoopGetCurrent())
-    l = m.location()
+        if not m.locationServicesEnabled():
+            raise LocationServiceException(
+                    'location services not enabled -- check privacy settings in System Preferences'  # noqa
+                )
 
-    # retry up to ten times, possibly sleeping between tries
-    for i in xrange(DEFAULT_RETRIES):
-        if l:
-            break
+        if not m.locationServicesAvailable():
+            raise LocationServiceException('location services not available')
 
-        time.sleep(float(timeout) / DEFAULT_RETRIES)
+        m.startUpdatingLocation()
         CoreLocation.CFRunLoopStop(CoreLocation.CFRunLoopGetCurrent())
         l = m.location()
 
-    if not l:
-        raise LocationServiceException(
-                'location could not be found -- is wifi enabled?'
-            )
+        # retry up to ten times, possibly sleeping between tries
+        for i in xrange(DEFAULT_RETRIES):
+            if l:
+                break
 
-    c = l.coordinate()
-    return Location(c.latitude, c.longitude)
+            time.sleep(float(timeout) / DEFAULT_RETRIES)
+            CoreLocation.CFRunLoopStop(CoreLocation.CFRunLoopGetCurrent())
+            l = m.location()
 
+        if not l:
+            raise LocationServiceException(
+                    'location could not be found -- is wifi enabled?'
+                )
+
+        c = l.coordinate()
+        return Location(c.latitude, c.longitude)
+
+@location_strategy("geoip")
 def geobytes_location(timeout=DEFAULT_TIMEOUT):
     external_ip = requests.get('http://jsonip.com/').json['ip']
     try:
             help='Suppress any error messages.')
     parser.add_option('--show', action='store_true',
             help='Show result on Google Maps in a browser.')
-    parser.add_option('--approx', action='store_true',
-            help='Use a GeoIP service if Core Location fails.')
+    parser.add_option('-f', '--force', action='store_true', dest='force',
+            help='Continue trying strategies if the first should fail')
+    parser.add_option('--strategy', action='store', dest='strategy',
+            help='Strategy for location lookup (corelocation|geoip)', default=LOCATION_STRATEGIES.keys()[0])
 
     return parser
 
         parser.print_help()
         sys.exit(1)
 
+    if options.strategy not in LOCATION_STRATEGIES:
+        raise OptionValueError("%s is not a valid strategy" % options.strategy)
+
     l = None
     error = None
+
+    strategy = LOCATION_STRATEGIES.pop(options.strategy)
+
     try:
-        l = location(options.timeout)
+        l = strategy(options.timeout)
     except LocationServiceException, e:
         error = e.message
 
-    if not l and options.approx:
-        try:
-            l = geobytes_location()
-        except LocationServiceException, e:
-            error = e.message
+    if not l and options.force:
+        for _, strategy in LOCATION_STRATEGIES:
+            try:
+                l = geobytes_location()
+            except LocationServiceException, e:
+                error = e.message
 
     if not l:
         if not options.quiet: