Start removing dependence on gflags.

Reviewed in https://codereview.appspot.com/7628044/.

This only removes the dependency from the core library, a second CL will
update all the samples.
diff --git a/oauth2client/tools.py b/oauth2client/tools.py
index 93b0171..839f296 100644
--- a/oauth2client/tools.py
+++ b/oauth2client/tools.py
@@ -24,7 +24,9 @@
 
 
 import BaseHTTPServer
-import gflags
+import argparse
+import logging
+import os
 import socket
 import sys
 import webbrowser
@@ -38,20 +40,31 @@
 except ImportError:
   from cgi import parse_qsl
 
+_CLIENT_SECRETS_MESSAGE = """WARNING: Please configure OAuth 2.0
 
-FLAGS = gflags.FLAGS
+To make this sample run you will need to populate the client_secrets.json file
+found at:
 
-gflags.DEFINE_boolean('auth_local_webserver', True,
-                      ('Run a local web server to handle redirects during '
-                       'OAuth authorization.'))
+   %s
 
-gflags.DEFINE_string('auth_host_name', 'localhost',
-                     ('Host name to use when running a local web server to '
-                      'handle redirects during OAuth authorization.'))
+with information from the APIs Console <https://code.google.com/apis/console>.
 
-gflags.DEFINE_multi_int('auth_host_port', [8080, 8090],
-                        ('Port to use when running a local web server to '
-                         'handle redirects during OAuth authorization.'))
+"""
+
+# run_parser is an ArgumentParser that contains command-line options expected
+# by tools.run(). Pass it in as part of the 'parents' argument to your own
+# ArgumentParser.
+argparser = argparse.ArgumentParser(add_help=False)
+argparser.add_argument('--auth_host_name', default='localhost',
+                        help='Hostname when running a local web server.')
+argparser.add_argument('--noauth_local_webserver', action='store_true',
+                        default=False, help='Do not run a local web server.')
+argparser.add_argument('--auth_host_port', default=[8080, 8090], type=int,
+                        nargs='*', help='Port web server should listen on.')
+argparser.add_argument('--logging_level', default='ERROR',
+                        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR',
+                                 'CRITICAL'],
+                        help='Set the logging level of detail.')
 
 
 class ClientRedirectServer(BaseHTTPServer.HTTPServer):
@@ -92,8 +105,8 @@
     pass
 
 
-@util.positional(2)
-def run(flow, storage, http=None):
+@util.positional(3)
+def run(flow, storage, flags, http=None):
   """Core code for a command-line application.
 
   The run() function is called from your application and runs through all the
@@ -121,32 +134,40 @@
       during OAuth authorization.
       (default: 'true')
 
-  Since it uses flags make sure to initialize the gflags module before calling
-  run().
+  The tools module defines an ArgumentParser the already contains the flag
+  definitions that run() requires. You can pass that ArgumentParser to your
+  ArgumentParser constructor:
+
+    parser = argparse.ArgumentParser(description=__doc__,
+        formatter_class=argparse.RawDescriptionHelpFormatter,
+        parents=[tools.run_parser])
+    flags = parser.parse_args(argv)
 
   Args:
     flow: Flow, an OAuth 2.0 Flow to step through.
     storage: Storage, a Storage to store the credential in.
+    flags: argparse.ArgumentParser, the command-line flags.
     http: An instance of httplib2.Http.request
          or something that acts like it.
 
   Returns:
     Credentials, the obtained credential.
   """
-  if FLAGS.auth_local_webserver:
+  logging.getLogger().setLevel(getattr(logging, flags.logging_level))
+  if not flags.noauth_local_webserver:
     success = False
     port_number = 0
-    for port in FLAGS.auth_host_port:
+    for port in flags.auth_host_port:
       port_number = port
       try:
-        httpd = ClientRedirectServer((FLAGS.auth_host_name, port),
+        httpd = ClientRedirectServer((flags.auth_host_name, port),
                                      ClientRedirectHandler)
       except socket.error, e:
         pass
       else:
         success = True
         break
-    FLAGS.auth_local_webserver = success
+    flags.noauth_local_webserver = not success
     if not success:
       print 'Failed to start a local webserver listening on either port 8080'
       print 'or port 9090. Please check your firewall settings and locally'
@@ -156,14 +177,14 @@
       print 'authorization.'
       print
 
-  if FLAGS.auth_local_webserver:
-    oauth_callback = 'http://%s:%s/' % (FLAGS.auth_host_name, port_number)
+  if not flags.noauth_local_webserver:
+    oauth_callback = 'http://%s:%s/' % (flags.auth_host_name, port_number)
   else:
     oauth_callback = OOB_CALLBACK_URN
   flow.redirect_uri = oauth_callback
   authorize_url = flow.step1_get_authorize_url()
 
-  if FLAGS.auth_local_webserver:
+  if not flags.noauth_local_webserver:
     webbrowser.open(authorize_url, new=1, autoraise=True)
     print 'Your browser has been opened to visit:'
     print
@@ -181,7 +202,7 @@
     print
 
   code = None
-  if FLAGS.auth_local_webserver:
+  if not flags.noauth_local_webserver:
     httpd.handle_request()
     if 'error' in httpd.query_params:
       sys.exit('Authentication request was rejected.')
@@ -203,3 +224,9 @@
   print 'Authentication successful.'
 
   return credential
+
+
+def message_if_missing(filename):
+  """Helpful message to display if the CLIENT_SECRETS file is missing."""
+
+  return _CLIENT_SECRETS_MESSAGE % filename
diff --git a/oauth2client/util.py b/oauth2client/util.py
index ee6a100..90dff15 100644
--- a/oauth2client/util.py
+++ b/oauth2client/util.py
@@ -22,9 +22,11 @@
 ]
 __all__ = [
   'positional',
+  'POSITIONAL_WARNING',
+  'POSITIONAL_EXCEPTION',
+  'POSITIONAL_IGNORE',
 ]
 
-import gflags
 import inspect
 import logging
 import types
@@ -38,12 +40,13 @@
 
 logger = logging.getLogger(__name__)
 
-FLAGS = gflags.FLAGS
+POSITIONAL_WARNING = 'WARNING'
+POSITIONAL_EXCEPTION = 'EXCEPTION'
+POSITIONAL_IGNORE = 'IGNORE'
+POSITIONAL_SET = frozenset([POSITIONAL_WARNING, POSITIONAL_EXCEPTION,
+                            POSITIONAL_IGNORE])
 
-gflags.DEFINE_enum('positional_parameters_enforcement', 'WARNING',
-    ['EXCEPTION', 'WARNING', 'IGNORE'],
-    'The action when an oauth2client.util.positional declaration is violated.')
-
+positional_parameters_enforcement = POSITIONAL_WARNING
 
 def positional(max_positional_args):
   """A decorator to declare that only the first N arguments my be positional.
@@ -93,10 +96,11 @@
         def my_method(cls, pos1, kwonly1=None):
           ...
 
-  The positional decorator behavior is controlled by the
-  --positional_parameters_enforcement flag. The flag may be set to 'EXCEPTION',
-  'WARNING' or 'IGNORE' to raise an exception, log a warning, or do nothing,
-  respectively, if a declaration is violated.
+  The positional decorator behavior is controlled by
+  util.positional_parameters_enforcement, which may be set to
+  POSITIONAL_EXCEPTION, POSITIONAL_WARNING or POSITIONAL_IGNORE to raise an
+  exception, log a warning, or do nothing, respectively, if a declaration is
+  violated.
 
   Args:
     max_positional_arguments: Maximum number of positional arguments. All
@@ -107,9 +111,9 @@
     being used as positional parameters.
 
   Raises:
-    TypeError if a key-word only argument is provided as a positional parameter,
-    but only if the --positional_parameters_enforcement flag is set to
-    'EXCEPTION'.
+    TypeError if a key-word only argument is provided as a positional
+    parameter, but only if util.positional_parameters_enforcement is set to
+    POSITIONAL_EXCEPTION.
   """
   def positional_decorator(wrapped):
     def positional_wrapper(*args, **kwargs):
@@ -119,9 +123,9 @@
           plural_s = 's'
         message = '%s() takes at most %d positional argument%s (%d given)' % (
             wrapped.__name__, max_positional_args, plural_s, len(args))
-        if FLAGS.positional_parameters_enforcement == 'EXCEPTION':
+        if positional_parameters_enforcement == POSITIONAL_EXCEPTION:
           raise TypeError(message)
-        elif FLAGS.positional_parameters_enforcement == 'WARNING':
+        elif positional_parameters_enforcement == POSITIONAL_WARNING:
           logger.warning(message)
         else: # IGNORE
           pass