def authenticate(auth_manager, options, config, section_header): """Set a (presumably valid) OAuth token for the client to use. Args: auth_manager: Object handling the authentication process. options: Parsed command line options. config: Configuration file parser. section_header: Section header to look in for the configuration file. Returns: True if authenticated, False otherwise. """ # Only try to set the access token if we're not forced to authenticate. # XXX: logic in here is iffy. Don't bother checking access token if it's not # set if not options.force_auth: set_token = auth_manager.set_access_token() if set_token: LOG.debug('Successfully set token') skip_auth = (options.skip_auth or config.lazy_get( section_header, 'skip_auth', default=False, option_type=bool)) else: LOG.debug('Failed to set token!') skip_auth = False else: LOG.debug('Forcing retrieval of new token') skip_auth = False if options.force_auth or not skip_auth: LOG.debug('Checking access token...') valid_token = auth_manager.check_access_token() if not valid_token: display_name = auth_manager.get_display_name(options.hostid) browser_str = config.lazy_get(section_header, 'auth_browser', default=None) if browser_str: if browser_str.lower() == 'disabled' or browser_str.lower( ) == 'none': browser = None else: try: browser = webbrowser.get(browser_str) except webbrowser.Error, err: LOG.warn( safe_encode(u'Could not get browser "%s": %s' % (browser_str, err))) browser = None else: try: browser = webbrowser.get() except webbrowser.Error, err: LOG.warn( safe_encode(u'Could not get default browser: %s' % err)) browser = None valid_token = auth_manager.retrieve_access_token( display_name, browser)
def authenticate(auth_manager, options, config, section_header): """Set a (presumably valid) OAuth token for the client to use. Args: auth_manager: Object handling the authentication process. options: Parsed command line options. config: Configuration file parser. section_header: Section header to look in for the configuration file. Returns: True if authenticated, False otherwise. """ # Only try to set the access token if we're not forced to authenticate. # XXX: logic in here is iffy. Don't bother checking access token if it's not # set if not options.force_auth: set_token = auth_manager.set_access_token() if set_token: LOG.debug('Successfully set token') skip_auth = (options.skip_auth or config.lazy_get(section_header, 'skip_auth', default=False, option_type=bool)) else: LOG.debug('Failed to set token!') skip_auth = False else: LOG.debug('Forcing retrieval of new token') skip_auth = False if options.force_auth or not skip_auth: LOG.debug('Checking access token...') valid_token = auth_manager.check_access_token() if not valid_token: display_name = auth_manager.get_display_name(options.hostid) browser_str = config.lazy_get(section_header, 'auth_browser', default=None) if browser_str: if browser_str.lower() == 'disabled' or browser_str.lower() == 'none': browser = None else: try: browser = webbrowser.get(browser_str) except webbrowser.Error, err: LOG.warn(safe_encode(u'Could not get browser "%s": %s' % (browser_str, err))) browser = None else: try: browser = webbrowser.get() except webbrowser.Error, err: LOG.warn(safe_encode( u'Could not get default browser: %s' % err)) browser = None valid_token = auth_manager.retrieve_access_token( display_name, browser)
def __init__(self, email): self.email = email # Loads config options config = googlecl.config.load_configuration(None) self.client_id = config.lazy_get( None, "client_id", default="20958643459.apps.googleusercontent.com", option_type=str ) self.client_secret = config.lazy_get(None, "client_secret", default="3D1TrF0sgq52J7zH80jdfbit", option_type=str) self.devkey2 = config.lazy_get( None, "devkey2", default="AIzaSyAmK-fJLcJ0jS2mMIX5EXgU6M6UPT39e50", option_type=str ) # Should make ^ required self.prompt = config.lazy_get(None, "prompt", default="required", option_type=str) self.editmode = config.lazy_get(None, "editmode", default="cl", option_type=str) self.formatting = config.lazy_get(None, "formatting", default="pprint", option_type=str) self.local_apis = config.lazy_get(None, "local_apis", default="", option_type=str) if "[" in self.local_apis or "(" in self.local_apis: self.local_apis = json.loads(self.local_apis) self.base_url = config.lazy_get(None, "base_url", default="https://www.googleapis.com", option_type=str) editor = config.safe_get("DOCS", "document_editor") if not editor: editor = config.safe_get(None, "editor") if not editor: import os editor = os.getenv("EDITOR") if not editor: editor = "vim" self.editor = editor
def __init__(self, email): self.email = email # Loads config options config = googlecl.config.load_configuration(None) self.client_id = config.lazy_get(None, 'client_id', default='20958643459.apps.googleusercontent.com', option_type=str) self.client_secret = config.lazy_get(None, 'client_secret', default='3D1TrF0sgq52J7zH80jdfbit', option_type=str) self.devkey2 = config.lazy_get(None, 'devkey2', default='AIzaSyAmK-fJLcJ0jS2mMIX5EXgU6M6UPT39e50', option_type=str) # Should make ^ required self.prompt = config.lazy_get(None, 'prompt', default='required', option_type=str) self.editmode = config.lazy_get(None, 'editmode', default='cl', option_type=str) self.formatting = config.lazy_get(None, 'formatting', default='pprint', option_type=str) self.local_apis = config.lazy_get(None, 'local_apis', default='', option_type=str) if '[' in self.local_apis or '(' in self.local_apis: self.local_apis = json.loads(self.local_apis) self.base_url = config.lazy_get(None, 'base_url', default='https://www.googleapis.com', option_type=str) editor = config.safe_get('DOCS', 'document_editor') if not editor: editor = config.safe_get(None, 'editor') if not editor: import os editor = os.getenv('EDITOR') if not editor: editor = 'vim' self.editor = editor
def _retrieve_value(attr, service_header): """Retrieve value from config file or user prompt.""" value = config.lazy_get(service_header, attr) if value: return value else: return raw_input('Please specify ' + attr + ': ')
def fill_out_options(args, service_header, task, options, config): """Fill out required options via config file and command line prompts. If there are any required fields missing for a task, fill them in. This is attempted by checking the following sources, in order: 1) The service_header section of the preferences file. 2) The arguments list given to this function. 3) Prompting the user. Note that 'user' and 'hostid' are special options -- they are always required, and they will skip step (2) when checking sources as mentioned above. Keyword arguments: args: list Arguments that may be options. service_header: str Name of the section in the config file for the active service. task: Requirements of the task (see class googlecl.service.Task). options: Contains attributes that have been specified already, typically through options on the command line (see setup_parser()). config: Configuration file parser. Returns: Nothing, though options may be modified to hold the required fields. """ def _retrieve_value(attr, service_header): """Retrieve value from config file or user prompt.""" value = config.lazy_get(service_header, attr) if value: return value else: return raw_input('Please specify ' + attr + ': ') if options.user is None: options.user = _retrieve_value('user', service_header) if options.hostid is None: options.hostid = _retrieve_value('hostid', service_header) missing_reqs = task.get_outstanding_requirements(options) LOG.debug('missing_reqs: ' + str(missing_reqs)) for attr in missing_reqs: value = config.lazy_get(service_header, attr) if not value: if args: value = args.pop(0) else: value = raw_input('Please specify ' + attr + ': ') setattr(options, attr, value) # Expand those options that might be a filename in disguise. max_file_size = 500000 # Value picked arbitrarily - no idea what the max # size in bytes of a summary is. if options.summary and os.path.exists(os.path.expanduser(options.summary)): with open(options.summary, 'r') as summary_file: options.summary = summary_file.read(max_file_size) if options.devkey and os.path.exists(os.path.expanduser(options.devkey)): with open(options.devkey, 'r') as key_file: options.devkey = key_file.read(max_file_size).strip()
def get_picasa_client(self): config = googlecl.config.load_configuration() self.clients = [] for i in xrange(self.cl_args.threads): client = picasa_service.SERVICE_CLASS(config) client.debug = self.cl_args.debug client.email = config.lazy_get(picasa.SECTION_HEADER, 'user') auth_manager = googlecl.authentication.AuthenticationManager('picasa', client) set_token = auth_manager.set_access_token() if not set_token: self.LOG.error('Error using OAuth token. You have to authenticate with googlecl using "google picasa list-albums --force-auth" and following the instructions') self.clients.append(client)
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
section_header is the name of the section in the config file that contains options specific to the service. config is a configuration file parser. """ LOG.debug('Your pythonpath: ' + str(os.environ.get('PYTHONPATH'))) try: package = import_at_runtime('googlecl.' + service) except ImportError, err: LOG.error(err.args[0]) LOG.error('Did you specify the service correctly? Must be one of ' + str(AVAILABLE_SERVICES)[1:-1]) return (None, None, None, None) config = googlecl.config.load_configuration(config_file_path) force_gdata_v1 = config.lazy_get(package.SECTION_HEADER, 'force_gdata_v1', default=False, option_type=bool) if force_gdata_v1: service_module = import_at_runtime('googlecl.' + service + '.service') else: try: service_module = import_at_runtime('googlecl.' + service + '.client') except ImportError: service_module = import_at_runtime('googlecl.' + service + '.service') return (service_module.SERVICE_CLASS, package.TASKS, package.SECTION_HEADER, config)
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
section_header is the name of the section in the config file that contains options specific to the service. config is a configuration file parser. """ LOG.debug('Your pythonpath: ' + str(os.environ.get('PYTHONPATH'))) try: package = import_at_runtime('googlecl.' + service) except ImportError, err: LOG.error(err.args[0]) LOG.error('Did you specify the service correctly? Must be one of ' + str(AVAILABLE_SERVICES)[1:-1]) return (None, None, None, None) config = googlecl.config.load_configuration(config_file_path) force_gdata_v1 = config.lazy_get(package.SECTION_HEADER, 'force_gdata_v1', default=False, option_type=bool) if force_gdata_v1: service_module = import_at_runtime('googlecl.' + service + '.service') else: try: service_module = import_at_runtime( 'googlecl.' + service + '.client') except ImportError: service_module = import_at_runtime( 'googlecl.' + service + '.service') return (service_module.SERVICE_CLASS, package.TASKS, package.SECTION_HEADER, config)