thirdparty/google_appengine/google/appengine/tools/appcfg.py
changeset 2273 e4cb9c53db3e
parent 2172 ac7bd3b467ff
child 2309 be1b94099f2d
equal deleted inserted replaced
2272:26491ee91e33 2273:e4cb9c53db3e
    51 from google.appengine.api import validation
    51 from google.appengine.api import validation
    52 from google.appengine.api import yaml_errors
    52 from google.appengine.api import yaml_errors
    53 from google.appengine.api import yaml_object
    53 from google.appengine.api import yaml_object
    54 from google.appengine.datastore import datastore_index
    54 from google.appengine.datastore import datastore_index
    55 from google.appengine.tools import appengine_rpc
    55 from google.appengine.tools import appengine_rpc
       
    56 from google.appengine.tools import bulkloader
    56 
    57 
    57 
    58 
    58 MAX_FILES_TO_CLONE = 100
    59 MAX_FILES_TO_CLONE = 100
    59 LIST_DELIMITER = "\n"
    60 LIST_DELIMITER = "\n"
    60 TUPLE_DELIMITER = "|"
    61 TUPLE_DELIMITER = "|"
  1154     assert self.deployed, "Deploy() must be called before IsReady()."
  1155     assert self.deployed, "Deploy() must be called before IsReady()."
  1155 
  1156 
  1156     StatusUpdate("Closing update: new version is ready to start serving.")
  1157     StatusUpdate("Closing update: new version is ready to start serving.")
  1157     self.server.Send("/api/appversion/startserving",
  1158     self.server.Send("/api/appversion/startserving",
  1158                      app_id=self.app_id, version=self.version)
  1159                      app_id=self.app_id, version=self.version)
       
  1160     self.in_transaction = False
  1159 
  1161 
  1160   def Rollback(self):
  1162   def Rollback(self):
  1161     """Rolls back the transaction if one is in progress."""
  1163     """Rolls back the transaction if one is in progress."""
  1162     if not self.in_transaction:
  1164     if not self.in_transaction:
  1163       return
  1165       return
  1468     parser.add_option("--noisy", action="store_const", const=3,
  1470     parser.add_option("--noisy", action="store_const", const=3,
  1469                       dest="verbose", help="Print all logs.")
  1471                       dest="verbose", help="Print all logs.")
  1470     parser.add_option("-s", "--server", action="store", dest="server",
  1472     parser.add_option("-s", "--server", action="store", dest="server",
  1471                       default="appengine.google.com",
  1473                       default="appengine.google.com",
  1472                       metavar="SERVER", help="The server to connect to.")
  1474                       metavar="SERVER", help="The server to connect to.")
       
  1475     parser.add_option("--secure", action="store_true", dest="secure",
       
  1476                       default=False,
       
  1477                       help="Use SSL when communicating with the server.")
  1473     parser.add_option("-e", "--email", action="store", dest="email",
  1478     parser.add_option("-e", "--email", action="store", dest="email",
  1474                       metavar="EMAIL", default=None,
  1479                       metavar="EMAIL", default=None,
  1475                       help="The username to use. Will prompt if omitted.")
  1480                       help="The username to use. Will prompt if omitted.")
  1476     parser.add_option("-H", "--host", action="store", dest="host",
  1481     parser.add_option("-H", "--host", action="store", dest="host",
  1477                       metavar="HOST", default=None,
  1482                       metavar="HOST", default=None,
  1555     return self.rpc_server_class(self.options.server, GetUserCredentials,
  1560     return self.rpc_server_class(self.options.server, GetUserCredentials,
  1556                                  GetUserAgent(), GetSourceName(),
  1561                                  GetUserAgent(), GetSourceName(),
  1557                                  host_override=self.options.host,
  1562                                  host_override=self.options.host,
  1558                                  save_cookies=self.options.save_cookies,
  1563                                  save_cookies=self.options.save_cookies,
  1559                                  auth_tries=auth_tries,
  1564                                  auth_tries=auth_tries,
  1560                                  account_type="HOSTED_OR_GOOGLE")
  1565                                  account_type="HOSTED_OR_GOOGLE",
       
  1566                                  secure=self.options.secure)
  1561 
  1567 
  1562   def _FindYaml(self, basepath, file_name):
  1568   def _FindYaml(self, basepath, file_name):
  1563     """Find yaml files in application directory.
  1569     """Find yaml files in application directory.
  1564 
  1570 
  1565     Args:
  1571     Args:
  1820     if now is None:
  1826     if now is None:
  1821       now = datetime.datetime.now()
  1827       now = datetime.datetime.now()
  1822 
  1828 
  1823     basepath = self.args[0]
  1829     basepath = self.args[0]
  1824     cron_entries = self._ParseCronYaml(basepath)
  1830     cron_entries = self._ParseCronYaml(basepath)
  1825     if cron_entries:
  1831     if cron_entries and cron_entries.cron:
  1826       for entry in cron_entries.cron:
  1832       for entry in cron_entries.cron:
  1827         description = entry.description
  1833         description = entry.description
  1828         if not description:
  1834         if not description:
  1829           description = "<no description>"
  1835           description = "<no description>"
  1830         print >>output, "\n%s:\nURL: %s\nSchedule: %s" % (description,
  1836         print >>output, "\n%s:\nURL: %s\nSchedule: %s" % (description,
  1831                                                           entry.url,
  1837                                                           entry.schedule,
  1832                                                           entry.schedule)
  1838                                                           entry.url)
  1833         schedule = groctimespecification.GrocTimeSpecification(entry.schedule)
  1839         schedule = groctimespecification.GrocTimeSpecification(entry.schedule)
  1834         matches = schedule.GetMatches(now, self.options.num_runs)
  1840         matches = schedule.GetMatches(now, self.options.num_runs)
  1835         for match in matches:
  1841         for match in matches:
  1836           print >>output, "%s, %s from now" % (
  1842           print >>output, "%s, %s from now" % (
  1837               match.strftime("%Y-%m-%d %H:%M:%S"), match - now)
  1843               match.strftime("%Y-%m-%d %H:%M:%S"), match - now)
  1844     """
  1850     """
  1845     parser.add_option("-n", "--num_runs", type="int", dest="num_runs",
  1851     parser.add_option("-n", "--num_runs", type="int", dest="num_runs",
  1846                       action="store", default=5,
  1852                       action="store", default=5,
  1847                       help="Number of runs of each cron job to display"
  1853                       help="Number of runs of each cron job to display"
  1848                       "Default is 5")
  1854                       "Default is 5")
       
  1855 
       
  1856   def _CheckRequiredUploadOptions(self):
       
  1857     """Checks that upload options are present."""
       
  1858     for option in ["filename", "kind", "config_file"]:
       
  1859       if getattr(self.options, option) is None:
       
  1860         self.parser.error("Option '%s' is required." % option)
       
  1861     if not self.options.url:
       
  1862       self.parser.error("You must have google.appengine.ext.remote_api.handler "
       
  1863                         "assigned to an endpoint in app.yaml, or provide "
       
  1864                         "the url of the handler via the 'url' option.")
       
  1865 
       
  1866   def InferUploadUrl(self, appyaml):
       
  1867     """Uses app.yaml to determine the remote_api endpoint.
       
  1868 
       
  1869     Args:
       
  1870       appyaml: A parsed app.yaml file.
       
  1871 
       
  1872     Returns:
       
  1873       The url of the remote_api endpoint as a string, or None
       
  1874     """
       
  1875     handlers = appyaml.handlers
       
  1876     handler_suffix = "remote_api/handler.py"
       
  1877     app_id = appyaml.application
       
  1878     for handler in handlers:
       
  1879       if hasattr(handler, "script") and handler.script:
       
  1880         if handler.script.endswith(handler_suffix):
       
  1881           server = self.options.server
       
  1882           if server == "appengine.google.com":
       
  1883             return "http://%s.appspot.com%s" % (app_id, handler.url)
       
  1884           else:
       
  1885             return "http://%s%s" % (server, handler.url)
       
  1886     return None
       
  1887 
       
  1888   def RunBulkloader(self, **kwargs):
       
  1889     """Invokes the bulkloader with the given keyword arguments.
       
  1890 
       
  1891     Args:
       
  1892       kwargs: Keyword arguments to pass to bulkloader.Run().
       
  1893     """
       
  1894     try:
       
  1895       import sqlite3
       
  1896     except ImportError:
       
  1897       logging.error("upload_data action requires SQLite3 and the python "
       
  1898                     "sqlite3 module (included in python since 2.5).")
       
  1899       sys.exit(1)
       
  1900 
       
  1901     sys.exit(bulkloader.Run(kwargs))
       
  1902 
       
  1903   def PerformUpload(self, run_fn=None):
       
  1904     """Performs a datastore upload via the bulkloader.
       
  1905 
       
  1906     Args:
       
  1907       run_fn: Function to invoke the bulkloader, used for testing.
       
  1908     """
       
  1909     if run_fn is None:
       
  1910       run_fn = self.RunBulkloader
       
  1911 
       
  1912     if len(self.args) != 1:
       
  1913       self.parser.error("Expected <directory> argument.")
       
  1914 
       
  1915     basepath = self.args[0]
       
  1916     appyaml = self._ParseAppYaml(basepath)
       
  1917 
       
  1918     self.options.app_id = appyaml.application
       
  1919 
       
  1920     if not self.options.url:
       
  1921       url = self.InferUploadUrl(appyaml)
       
  1922       if url is not None:
       
  1923         self.options.url = url
       
  1924 
       
  1925     self._CheckRequiredUploadOptions()
       
  1926 
       
  1927     if self.options.batch_size < 1:
       
  1928       self.parser.error("batch_size must be 1 or larger.")
       
  1929 
       
  1930     if verbosity == 1:
       
  1931       logging.getLogger().setLevel(logging.INFO)
       
  1932       self.options.debug = False
       
  1933     else:
       
  1934       logging.getLogger().setLevel(logging.DEBUG)
       
  1935       self.options.debug = True
       
  1936 
       
  1937     StatusUpdate("Uploading data records.")
       
  1938 
       
  1939     run_fn(app_id=self.options.app_id,
       
  1940            url=self.options.url,
       
  1941            filename=self.options.filename,
       
  1942            batch_size=self.options.batch_size,
       
  1943            kind=self.options.kind,
       
  1944            num_threads=self.options.num_threads,
       
  1945            bandwidth_limit=self.options.bandwidth_limit,
       
  1946            rps_limit=self.options.rps_limit,
       
  1947            http_limit=self.options.http_limit,
       
  1948            db_filename=self.options.db_filename,
       
  1949            config_file=self.options.config_file,
       
  1950            auth_domain=self.options.auth_domain,
       
  1951            has_header=self.options.has_header,
       
  1952            loader_opts=self.options.loader_opts,
       
  1953            log_file=self.options.log_file,
       
  1954            passin=self.options.passin,
       
  1955            email=self.options.email,
       
  1956            debug=self.options.debug,
       
  1957 
       
  1958            exporter_opts=None,
       
  1959            download=False,
       
  1960            result_db_filename=None,
       
  1961            )
       
  1962 
       
  1963   def _PerformUploadOptions(self, parser):
       
  1964     """Adds 'upload_data' specific options to the 'parser' passed in.
       
  1965 
       
  1966     Args:
       
  1967       parser: An instance of OptionsParser.
       
  1968     """
       
  1969     parser.add_option("--filename", type="string", dest="filename",
       
  1970                       action="store",
       
  1971                       help="The name of the file containing the input data."
       
  1972                       " (Required)")
       
  1973     parser.add_option("--config_file", type="string", dest="config_file",
       
  1974                       action="store",
       
  1975                       help="Name of the configuration file. (Required)")
       
  1976     parser.add_option("--kind", type="string", dest="kind",
       
  1977                       action="store",
       
  1978                       help="The kind of the entities to store. (Required)")
       
  1979     parser.add_option("--url", type="string", dest="url",
       
  1980                       action="store",
       
  1981                       help="The location of the remote_api endpoint.")
       
  1982     parser.add_option("--num_threads", type="int", dest="num_threads",
       
  1983                       action="store", default=10,
       
  1984                       help="Number of threads to upload records with.")
       
  1985     parser.add_option("--batch_size", type="int", dest="batch_size",
       
  1986                       action="store", default=10,
       
  1987                       help="Number of records to post in each request.")
       
  1988     parser.add_option("--bandwidth_limit", type="int", dest="bandwidth_limit",
       
  1989                       action="store", default=250000,
       
  1990                       help="The maximum bytes/second bandwidth for transfers.")
       
  1991     parser.add_option("--rps_limit", type="int", dest="rps_limit",
       
  1992                       action="store", default=20,
       
  1993                       help="The maximum records/second for transfers.")
       
  1994     parser.add_option("--http_limit", type="int", dest="http_limit",
       
  1995                       action="store", default=8,
       
  1996                       help="The maximum requests/second for transfers.")
       
  1997     parser.add_option("--db_filename", type="string", dest="db_filename",
       
  1998                       action="store",
       
  1999                       help="Name of the progress database file.")
       
  2000     parser.add_option("--auth_domain", type="string", dest="auth_domain",
       
  2001                       action="store", default="gmail.com",
       
  2002                       help="The name of the authorization domain to use.")
       
  2003     parser.add_option("--has_header", dest="has_header",
       
  2004                       action="store_true", default=False,
       
  2005                       help="Whether the first line of the input file should be"
       
  2006                       " skipped")
       
  2007     parser.add_option("--loader_opts", type="string", dest="loader_opts",
       
  2008                       help="A string to pass to the Loader.Initialize method.")
       
  2009     parser.add_option("--log_file", type="string", dest="log_file",
       
  2010                       help="File to write bulkloader logs.  If not supplied "
       
  2011                            "then a new log file will be created, named: "
       
  2012                            "bulkloader-log-TIMESTAMP.")
  1849 
  2013 
  1850   class Action(object):
  2014   class Action(object):
  1851     """Contains information about a command line action.
  2015     """Contains information about a command line action.
  1852 
  2016 
  1853     Attributes:
  2017     Attributes:
  1951           short_desc="Display information about cron jobs.",
  2115           short_desc="Display information about cron jobs.",
  1952           long_desc="""
  2116           long_desc="""
  1953 The 'cron_info' command will display the next 'number' runs (default 5) for
  2117 The 'cron_info' command will display the next 'number' runs (default 5) for
  1954 each cron job defined in the cron.yaml file."""),
  2118 each cron job defined in the cron.yaml file."""),
  1955 
  2119 
       
  2120       "upload_data": Action(
       
  2121           function="PerformUpload",
       
  2122           usage="%prog [options] upload_data <directory>",
       
  2123           options=_PerformUploadOptions,
       
  2124           short_desc="Upload CSV records to datastore",
       
  2125           long_desc="""
       
  2126 The 'upload_data' command translates CSV records into datastore entities and
       
  2127 uploads them into your application's datastore."""),
       
  2128 
  1956 
  2129 
  1957 
  2130 
  1958   }
  2131   }
  1959 
  2132 
  1960 
  2133