| Index: third_party/oauth2client/file.py | 
| diff --git a/third_party/oauth2client/file.py b/third_party/oauth2client/file.py | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..1895f94eac58d0386ce59baa86295d27a8a79ec3 | 
| --- /dev/null | 
| +++ b/third_party/oauth2client/file.py | 
| @@ -0,0 +1,124 @@ | 
| +# Copyright (C) 2010 Google Inc. | 
| +# | 
| +# Licensed under the Apache License, Version 2.0 (the "License"); | 
| +# you may not use this file except in compliance with the License. | 
| +# You may obtain a copy of the License at | 
| +# | 
| +#      http://www.apache.org/licenses/LICENSE-2.0 | 
| +# | 
| +# Unless required by applicable law or agreed to in writing, software | 
| +# distributed under the License is distributed on an "AS IS" BASIS, | 
| +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| +# See the License for the specific language governing permissions and | 
| +# limitations under the License. | 
| + | 
| +"""Utilities for OAuth. | 
| + | 
| +Utilities for making it easier to work with OAuth 2.0 | 
| +credentials. | 
| +""" | 
| + | 
| +__author__ = 'jcgregorio@google.com (Joe Gregorio)' | 
| + | 
| +import os | 
| +import stat | 
| +import threading | 
| + | 
| +from anyjson import simplejson | 
| +from client import Storage as BaseStorage | 
| +from client import Credentials | 
| + | 
| + | 
| +class CredentialsFileSymbolicLinkError(Exception): | 
| +  """Credentials files must not be symbolic links.""" | 
| + | 
| + | 
| +class Storage(BaseStorage): | 
| +  """Store and retrieve a single credential to and from a file.""" | 
| + | 
| +  def __init__(self, filename): | 
| +    self._filename = filename | 
| +    self._lock = threading.Lock() | 
| + | 
| +  def _validate_file(self): | 
| +    if os.path.islink(self._filename): | 
| +      raise CredentialsFileSymbolicLinkError( | 
| +          'File: %s is a symbolic link.' % self._filename) | 
| + | 
| +  def acquire_lock(self): | 
| +    """Acquires any lock necessary to access this Storage. | 
| + | 
| +    This lock is not reentrant.""" | 
| +    self._lock.acquire() | 
| + | 
| +  def release_lock(self): | 
| +    """Release the Storage lock. | 
| + | 
| +    Trying to release a lock that isn't held will result in a | 
| +    RuntimeError. | 
| +    """ | 
| +    self._lock.release() | 
| + | 
| +  def locked_get(self): | 
| +    """Retrieve Credential from file. | 
| + | 
| +    Returns: | 
| +      oauth2client.client.Credentials | 
| + | 
| +    Raises: | 
| +      CredentialsFileSymbolicLinkError if the file is a symbolic link. | 
| +    """ | 
| +    credentials = None | 
| +    self._validate_file() | 
| +    try: | 
| +      f = open(self._filename, 'rb') | 
| +      content = f.read() | 
| +      f.close() | 
| +    except IOError: | 
| +      return credentials | 
| + | 
| +    try: | 
| +      credentials = Credentials.new_from_json(content) | 
| +      credentials.set_store(self) | 
| +    except ValueError: | 
| +      pass | 
| + | 
| +    return credentials | 
| + | 
| +  def _create_file_if_needed(self): | 
| +    """Create an empty file if necessary. | 
| + | 
| +    This method will not initialize the file. Instead it implements a | 
| +    simple version of "touch" to ensure the file has been created. | 
| +    """ | 
| +    if not os.path.exists(self._filename): | 
| +      old_umask = os.umask(0177) | 
| +      try: | 
| +        open(self._filename, 'a+b').close() | 
| +      finally: | 
| +        os.umask(old_umask) | 
| + | 
| +  def locked_put(self, credentials): | 
| +    """Write Credentials to file. | 
| + | 
| +    Args: | 
| +      credentials: Credentials, the credentials to store. | 
| + | 
| +    Raises: | 
| +      CredentialsFileSymbolicLinkError if the file is a symbolic link. | 
| +    """ | 
| + | 
| +    self._create_file_if_needed() | 
| +    self._validate_file() | 
| +    f = open(self._filename, 'wb') | 
| +    f.write(credentials.to_json()) | 
| +    f.close() | 
| + | 
| +  def locked_delete(self): | 
| +    """Delete Credentials file. | 
| + | 
| +    Args: | 
| +      credentials: Credentials, the credentials to store. | 
| +    """ | 
| + | 
| +    os.unlink(self._filename) | 
|  |