Mercurial > hg > smartopen
diff smartopen/smartopen.py @ 14:a62fbff067f8
start bringing this whole thing up to speed
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Wed, 01 May 2013 06:56:12 -0700 |
parents | 4dd12cf64c0e |
children |
line wrap: on
line diff
--- a/smartopen/smartopen.py Thu Apr 04 17:13:18 2013 -0700 +++ b/smartopen/smartopen.py Wed May 01 06:56:12 2013 -0700 @@ -1,31 +1,110 @@ #!/usr/bin/env python -""" smart open the data passed in """ +""" +open what you give in your browser +""" import os +import subprocess import sys from optparse import OptionParser from pkg_resources import iter_entry_points from ConfigParser import ConfigParser -def locations(names=None, config=None): + +### method to open a browser + +### It turns out finding the default browser is very hard :( +# webbrowser is standard...just...what does that mean? for gnome-terminal, +# I get firefox; however, despite what +# http://stackoverflow.com/questions/4216985/python-call-to-operating-system-to-open-url +# says (and also because of it), I actually get `links` from xdg-open(!) +# (which of course it doesn't even tell me) + +# xdg-settings --list +# Known properties: +# default-web-browser Default web browser +# xdg-settings get default-web-browser +# xdg-settings: unknown desktop environment + +# The solution....is here: +# http://askubuntu.com/questions/96080/how-to-set-google-chrome-as-the-default-browser/96081#96081 +# and indeed in ~/.local/share/applications/mimeapps.list +# I do have:: + +# text/html=firefox.desktop;thunderbird.desktop; + +# in `[Added Associations]` +# (fwiw, ``pprint(mailcap.getcaps())`` was interesting but not very useful, +# referencing /usr/bin/sensible-browser which is in fact links (!) + +# TODO: + +# probably some fancy module should be written that *actually* does what +# its supposed to here; maybe https://pypi.python.org/pypi/desktop is that +# fancy pants module; I don't know! pypi doesn't let me browse tarballs! +# in any case, this is mostly for me and it must be portable; + +# So what we'll actually do: +# (Not surprisingly, explicit wins) +# - if specified on the command line (which it can't be yet) that wins +# - use browser/BROWSER if set in config +# - if not...you're back to guessing +# - if `which` was stdlib I'd probably guess on that since I know I can't rely +# on `xdg-open`... +# - ...and there are other platforms; again, I don't care.... +# - so we're back to Firefox being #1 + +# Which despite my love for Firefox, I'd love to help with autoselection if +# anyone would throw their hat in + +# * let's not forget http://freedesktop.org/wiki/Software/pyxdg if we're +# talking about non-stdlib solutions for linux only + +def open_in_browser(url, browser=None): + """yeah, that's right...""" + + if browser is None: + browser = 'firefox' # we'll cheat because of course its easy + + # control via env variable; might as well keep it set o_O + os.environ.setdefault('BROWSER', browser) + # see e.g. http://hg.python.org/cpython/file/2.7/Lib/webbrowser.py + # sadly these are different:: + # xdg-open http://k0s.org/ + # BROWSER=firefox xdg-open http://k0s.org/ + + # now invoke the damn thing + import webbrowser + return webbrowser.open(url) # XXX lord almighty + # why bother returning it even? + + +### methods for inspecting the locations + +def locations(names=None, config=None, verbose=False): """ list of 2-tuples of location handlers; * names: order names of handlers * config: nested dictionary of configuration from names """ + # setup _handlers = {} _names = [] if config is None: config = {} - + + # load the handlers + # (really, these should come of a dict that is shared with an entry point) for i in iter_entry_points('smartopen.locations'): try: handler = i.load() - except: - continue # TODO: warn/debug with --verbose flag + except Exception, e: + if verbose: + print >> sys.stderr, "Error loading handler:\n%s" % e + continue _handlers[i.name] = handler if not names: _names.append(i.name) @@ -41,12 +120,17 @@ if _name in _handlers: try: handler = _handlers[_name](**config.get(name, {})) - except: + except Exception, e: + if verbose: + print >> sys.stderr, "blah blah blah" continue handlers.append((name, handler)) return handlers + def urls(query, handlers=None): + """returns available urls in order of preference for a query""" + if handlers is None: handlers = locations() urls = [] @@ -55,28 +139,41 @@ urls.append((name, handler.url(query))) return urls + def url(query, handlers=None): + """return the top url for a query""" + if handlers is None: handlers = locations() for name, handler in handlers: if handler.test(query): return handler.url(query) +### command line entry point + def main(args=sys.argv[1:]): # parse command line optioins - parser = OptionParser() + default_browser = os.environ.get('BROWSER', 'firefox') # ^ see LONG note above + usage = '%prog [options] query' + parser = OptionParser(usage=usage) + parser.add_option('-b', '--browser', dest='browser', + default=None, + help="browser to use; can also be set in config and BROWSER [default: %default]") parser.add_option('-c', '--config', dest="config", help="config file to read") - parser.add_option('-u', '--url', dest="url", + parser.add_option('-u', '--url', dest="url", action='store_true', default=False, help="print the first url handled") - parser.add_option('-a', '--all', dest="all", + parser.add_option('-a', '--all', dest="all", action='store_true', default=False, help="print all handlers that match the query") parser.add_option('-H', '--handler', dest="handlers", action='append', help="name of the handler to use, in order") + parser.add_option('-v', '--verbose', dest='verbose', + action='store_true', default=True, + help="be verbose with output") parser.add_option('--print-handlers', dest="print_handlers", action='store_true', help="print all handlers in order they would be tried") @@ -87,23 +184,34 @@ if not options.handlers: options.handlers = None - # config + # read config, if available config = ConfigParser() if not options.config: options.config = os.path.join(os.environ.get('HOME', ''), '.smartopen.ini') if os.path.exists(options.config): config.read(options.config) + + # select handlers if not options.handlers and config.has_option('DEFAULTS', 'handlers'): - options.handlers = [ i.strip() for i in config.get('DEFAULTS', 'handlers').split(',') ] + options.handlers = [i.strip() for i in config.get('DEFAULTS', 'handlers').split(',')] + + # select browser + if not options.browser: + for key in 'BROWSER', 'browser': + if config.has_option('DEFAULTS', key): + options.browser = config.get('DEFAULTS', key) + break + + # the remaining config is arguments to the handlers _config = {} for section in config.sections(): _config[section] = dict(config.items(section)) # get the handlers - _locations = locations(options.handlers, _config) + _locations = locations(options.handlers, _config, verbose=options.verbose) - # print the handlers if options.print_handlers: + # print the handlers for name, loc in _locations: print name sys.exit(0) @@ -112,26 +220,29 @@ if args: data = ' '.join(args) else: + # read from stdin data = sys.stdin.read() - # print the URLs if options.all: + # print the URLs _urls = urls(data, _locations) for name, _url in _urls: print '%s: %s' % (name, _url) sys.exit(0) + # select the url _url = url(data, _locations) - # print a URL if options.url: - print _url + # print a URL + print _url or 'No handler found for your query' sys.exit(0) # open the URL in a browser - os.system("firefox '%s'" % _url) - sys.exit(0) - + if _url: + open_in_browser(_url) + else: + parser.error("No handler found") if __name__ == '__main__': main()