def run_once(options, args): """Run one command. Keyword arguments: options: Options instance as built and returned by optparse. args: Arguments to GoogleCL, also as returned by optparse. """ global discovery # If we haven't gotten the list of discovery APIs yet, and they're asking for # a discovery API, figure out their email address and then get a list of # APIs. if apis and not discovery: if (args[0] not in AVAILABLE_SERVICES) or \ (args[0] == 'help' and len(args) == 1) or \ (args[0] == 'help' and len(args)>1 and \ args[1] not in AVAILABLE_SERVICES): # Is there a better approach than using the calendar API to get the email # address? service_class, tasks, section_header, config = import_service('calendar', None) email = config.lazy_get(section_header, 'user') discovery = DiscoveryManager(email) global AVAILABLE_APIS AVAILABLE_APIS = discovery.apis_list() init_args = args[:] try: service = args.pop(0) task_name = args.pop(0) except IndexError: if service == 'help': print_help() else: LOG.error('Must specify at least a service and a task!') return if apis and service == 'refresh' and task_name == 'apis': discovery.docManager.load(force=True) AVAILABLE_APIS = discovery.apis_list() return if apis and service == 'edit' and task_name == 'config': import subprocess subprocess.call((discovery.dataManager.editor, googlecl.config.get_config_path())) return if service == 'help' and task_name == 'more': print_more_help() return # Detects if GData is not provided a version number or the path is too long conflict = (task_name[0] == 'v' and task_name[1].isdigit()) or (service == 'help' and args) # Prioritizes using existing GData APIs over Discovery. # May have to change if/when those are brought over to Discovery... if service == 'help': if task_name in AVAILABLE_SERVICES and not conflict: service_class, tasks, section_header, config = import_service(task_name, options.config) if tasks: print_help(task_name, tasks) return else: if apis and task_name in AVAILABLE_APIS: discovery.run(init_args) elif not apis: LOG.error('Did not recognize service.') LOG.error('If you wanted a Discovery service, make sure you have') LOG.error('google-api-python-client installed.') else: LOG.error('Did not recognize service.') return elif service in AVAILABLE_SERVICES and not conflict: service_class, tasks, section_header, config = import_service(service, options.config) else: if apis and service in AVAILABLE_APIS: discovery.run(init_args) elif not apis: LOG.error('Did not recognize service.') LOG.error('If you wanted a Discovery service, make sure you have') LOG.error('google-api-python-client installed.') else: LOG.error('Did not recognize service.') return if not service_class: return client = service_class(config) # Activate debugging output from HTTP requests. "service" clients only! # "client" versions need to set self.http_client.debug in their own __init__ client.debug = config.lazy_get(section_header, 'debug', default=options.debug, option_type=bool) # XXX: Not the best place for this. if hasattr(client, 'http_client'): client.http_client.debug = client.debug try: task = tasks[task_name] task.name = task_name except KeyError: LOG.error('Did not recognize task, please use one of ' + \ str(tasks.keys())) return if 'devkey' in task.required: # If a devkey is required, and there is none specified via an option # BEFORE fill_out_options, insert the key from file or the key given # to GoogleCL. # You can get your own key at http://code.google.com/apis/youtube/dashboard if not options.devkey: options.devkey = googlecl.read_devkey() or 'AI39si4d9dBo0dX7TnGyfQ68bNiKfEeO7wORCfY3HAgSStFboTgTgAi9nQwJMfMSizdGIs35W9wVGkygEw8ei3_fWGIiGSiqnQ' # fill_out_options will read the key from file if necessary, but will not set # it since it will always get a non-empty value beforehand. fill_out_options(args, section_header, task, options, config) client.email = options.user if options.blog: config.set_missing_default(section_header, 'blog', options.blog) if options.devkey: client.developer_key = options.devkey # This may save an invalid dev key -- it's up to the user to specify a # valid dev key eventually. # TODO: It would be nice to make this more efficient. googlecl.write_devkey(options.devkey) # Unicode-ize options and args for attr_name in dir(options): attr = getattr(options, attr_name) if not attr_name.startswith('_') and isinstance(attr, str): setattr(options, attr_name, safe_decode(attr, googlecl.TERMINAL_ENCODING)) if args: args = [safe_decode(string, googlecl.TERMINAL_ENCODING) for string in args] # Expand options.src. The goal is to expand things like # --src=~/Photos/album1/* (which does not normally happen) # XXX: This ought to be in fill_out_options(), along with unicode-ize above. if options.src: expanded_args = glob.glob(options.src) if expanded_args: options.src = expanded_args else: options.src = [options.src] else: options.src = [] # Take a gander at the options filled in. if LOG.getEffectiveLevel() == logging.DEBUG: import inspect for attr_name in dir(options): if not attr_name.startswith('_'): attr = getattr(options, attr_name) if attr is not None and not inspect.ismethod(attr): LOG.debug(safe_encode('Option ' + attr_name + ': ' + unicode(attr))) LOG.debug(safe_encode('args: ' + unicode(args))) auth_manager = googlecl.authentication.AuthenticationManager(service, client) authenticated = authenticate(auth_manager, options, config, section_header) if not authenticated: LOG.debug('Authentication failed, exiting run_once') return -1 # If we've authenticated, save the config values we've been setting. # And remember the email address that worked! config.set_missing_default(section_header, 'user', client.email) config.write_out_parser() run_error = None try: task.run(client, options, args) except AttributeError, run_error: err_str = safe_decode(run_error) if err_str.startswith("'OAuth"): LOG.info('OAuth error. Try re-running with --force-auth.') else: raise run_error
def run_once(options, args): """Run one command. Keyword arguments: options: Options instance as built and returned by optparse. args: Arguments to GoogleCL, also as returned by optparse. """ global discovery # If we haven't gotten the list of discovery APIs yet, and they're asking for # a discovery API, figure out their email address and then get a list of # APIs. if apis and not discovery: if (args[0] not in AVAILABLE_SERVICES) or \ (args[0] == 'help' and len(args) == 1) or \ (args[0] == 'help' and len(args) > 1 and args[1] not in AVAILABLE_SERVICES): # Is there a better approach than using the calendar API to get the email # address? service_class, tasks, section_header, config = import_service('calendar', None) email = config.lazy_get(section_header, 'user') discovery = DiscoveryManager(email) global AVAILABLE_APIS AVAILABLE_APIS = discovery.apis_list() init_args = args[:] try: service = args.pop(0) task_name = args.pop(0) except IndexError: if service == 'help': print_help() else: LOG.error('Must specify at least a service and a task!') return if apis and service == 'refresh' and task_name == 'apis': discovery.docManager.load(force=True) AVAILABLE_APIS = discovery.apis_list() return if apis and service == 'edit' and task_name == 'config': import subprocess subprocess.call((discovery.dataManager.editor, googlecl.config.get_config_path())) return if service == 'help' and task_name == 'more': print_more_help() return # Detects if GData is not provided a version number or the path is too long conflict = (task_name[0] == 'v' and task_name[ 1].isdigit()) or (service == 'help' and args) # Prioritizes using existing GData APIs over Discovery. # May have to change if/when those are brought over to Discovery... if service == 'help': if task_name in AVAILABLE_SERVICES and not conflict: service_class, tasks, section_header, config = import_service(task_name, options.config) if tasks: print_help(task_name, tasks) return else: if apis and task_name in AVAILABLE_APIS: discovery.run(init_args) elif not apis: LOG.error('Did not recognize service.') LOG.error( 'If you wanted a Discovery service, make sure you have') LOG.error('google-api-python-client installed.') else: LOG.error('Did not recognize service.') return elif service in AVAILABLE_SERVICES and not conflict: service_class, tasks, section_header, config = import_service(service, options.config) else: if apis and service in AVAILABLE_APIS: discovery.run(init_args) elif not apis: LOG.error('Did not recognize service.') LOG.error('If you wanted a Discovery service, make sure you have') LOG.error('google-api-python-client installed.') else: LOG.error('Did not recognize service.') return if not service_class: return client = service_class(config) # Activate debugging output from HTTP requests. "service" clients only! # "client" versions need to set self.http_client.debug in their own __init__ client.debug = config.lazy_get(section_header, 'debug', default=options.debug, option_type=bool) # XXX: Not the best place for this. if hasattr(client, 'http_client'): client.http_client.debug = client.debug try: task = tasks[task_name] task.name = task_name except KeyError: LOG.error('Did not recognize task, please use one of ' + str(tasks.keys())) return if 'devkey' in task.required: # If a devkey is required, and there is none specified via an option # BEFORE fill_out_options, insert the key from file or the key given # to GoogleCL. # You can get your own key at # http://code.google.com/apis/youtube/dashboard if not options.devkey: options.devkey = googlecl.read_devkey( ) or 'AI39si4d9dBo0dX7TnGyfQ68bNiKfEeO7wORCfY3HAgSStFboTgTgAi9nQwJMfMSizdGIs35W9wVGkygEw8ei3_fWGIiGSiqnQ' # fill_out_options will read the key from file if necessary, but will not set # it since it will always get a non-empty value beforehand. fill_out_options(args, section_header, task, options, config) client.email = options.user if options.blog: config.set_missing_default(section_header, 'blog', options.blog) if options.devkey: client.developer_key = options.devkey # This may save an invalid dev key -- it's up to the user to specify a # valid dev key eventually. # TODO: It would be nice to make this more efficient. googlecl.write_devkey(options.devkey) # Unicode-ize options and args for attr_name in dir(options): attr = getattr(options, attr_name) if not attr_name.startswith('_') and isinstance(attr, str): setattr(options, attr_name, safe_decode( attr, googlecl.TERMINAL_ENCODING)) if args: args = [safe_decode(string, googlecl.TERMINAL_ENCODING) for string in args] # Expand options.src. The goal is to expand things like # --src=~/Photos/album1/* (which does not normally happen) # XXX: This ought to be in fill_out_options(), along with unicode-ize # above. if options.src: expanded_args = glob.glob(options.src) if expanded_args: options.src = expanded_args else: options.src = [options.src] else: options.src = [] # Take a gander at the options filled in. if LOG.getEffectiveLevel() == logging.DEBUG: import inspect for attr_name in dir(options): if not attr_name.startswith('_'): attr = getattr(options, attr_name) if attr is not None and not inspect.ismethod(attr): LOG.debug(safe_encode( 'Option ' + attr_name + ': ' + unicode(attr))) LOG.debug(safe_encode('args: ' + unicode(args))) auth_manager = googlecl.authentication.AuthenticationManager( service, client) authenticated = authenticate(auth_manager, options, config, section_header) if not authenticated: LOG.debug('Authentication failed, exiting run_once') return -1 # If we've authenticated, save the config values we've been setting. # And remember the email address that worked! config.set_missing_default(section_header, 'user', client.email) config.write_out_parser() run_error = None try: task.run(client, options, args) except AttributeError, run_error: err_str = safe_decode(run_error) if err_str.startswith("'OAuth"): LOG.info('OAuth error. Try re-running with --force-auth.') else: raise run_error