Addressed Sverre's commits on the previous commit.
authorTodd Larsen <tlarsen@google.com>
Mon, 09 Jun 2008 23:49:20 +0000
changeset 48 39e1c8a54b37
parent 47 a237c3c5763e
child 49 7b6914018044
Addressed Sverre's commits on the previous commit. Patch by: Todd Larsen Review by: Sverre Rabbelier Review issue: 282 Review URL: http://codereviews.googleopensourceprograms.com/282
scripts/app_image.py
--- a/scripts/app_image.py	Fri Jun 06 04:30:49 2008 +0000
+++ b/scripts/app_image.py	Mon Jun 09 23:49:20 2008 +0000
@@ -15,6 +15,61 @@
 # limitations under the License.
 
 """Functions used by multiple scripts to form Google App Engine images.
+
+These utility functions are used by multiple scripts for creating and managing
+Google App Engine "uploadable image" directories produced by combining a
+specific Melange application (for example: trunk/apps/proto, trunk/apps/gsoc,
+trunk/apps/ghop, etc.), the SoC framework in trunk/soc, and any /thirdparty/
+packages, such as thirdparty/django.
+
+The directory layout expected by Google App Engine is (approximately):
+  <app>/
+        app.yaml
+        index.yaml
+        content/     (a static content directory for the Melange application)
+        main.py      (a WSGI wrapper for Django-based Google App Engine apps)
+        settings.py  (application-specific Django settings)
+        urls.py      (application-specific URL handler mappings)
+
+The application itself can have application-specific code and templates, so
+there is an additional subdirectory with the same name as the application
+(to disambiguate modules in the Melange application with same-named modules
+in the SoC framework):
+  <app>/
+        <app>/
+              models/, templates/, views/, etc.
+
+Google App Engine assumes that the root of package paths is <app>/, so all
+packages are placed in sub-directories of <app>/, and the SoC framework
+is considered a package:
+  <app>/
+        soc/
+            models/, templates/, views/, etc.
+
+For Django template based applications (which Melange applications are),
+include the django distribution directory (which is one of the /thirdparty/
+packages) and some Django-specific files:
+  <app>/
+        django/
+               core/, db/, dispatch/, etc.
+
+Any other /thirdparty/ packages would be included in the the Google App Engine
+"uploadable image" directory similarly to Django above.
+
+
+A NOTE ABOUT DIRECTORY NAMES RETURNED BY FUNCTIONS IN THIS MODULE
+
+The functions in this module return directory names with a trailing / svn path
+separator.  This is done by convention only (svn_helper functions normalize
+the path names of directories in this same way).  The trailing separator is
+kept to make it easier to combine paths (since the caller can always assume
+directories end with the / separator) and to make it easier to distinguish
+directories from files in human-readable output.
+
+Some pysvn Client methods accept directories named this way, others raise
+exceptions and expect a "canonical" form that does not include the trailing
+/ separator.  This does not seem to be documented in the pysvn documentation,
+so the trailing separator is removed in svn_helper when necessary.
 """
 
 __authors__ = [
@@ -23,37 +78,71 @@
 ]
 
 
+import sys
+
 from trunk.scripts import svn_helper
 
 
 def getRepoAppPath(repo, app):
   """Returns path to specified Melange app in the supplied svn repository.
+
+  Args:
+    repo: SVN repository URL
+    app: Melange application name (expected to exist in trunk/apps)
   """
-  return '%strunk/apps/%s' % (repo, app)
+  # see note about directory names ending with / svn path separators in the
+  # module __doc__ string
+  return svn_helper.formatDirPath('%strunk/apps/%s' % (
+      svn_helper.formatDirPath(repo), app))
 
 
 def getRepoThirdPartyPath(repo):
   """Returns path to third-party packages in the supplied svn repository.
+
+  Args:
+    repo: SVN repository URL
   """
-  return '%sthirdparty/' % repo
+  # see note about directory names ending with / svn path separators in the
+  # module __doc__ string
+  return '%sthirdparty/' % svn_helper.formatDirPath(repo)
 
 
-def getThirdPartyPackageNames(pkg_path, **kwargs):
+def getThirdPartyPackageNames(pkg_path, **svn_kwargs):
   """Returns a list of third-party packages in the supplied URL.
+
+  Args:
+    pkg_path: full SVN URL path to the directory containing third-party
+      packages, usually the path formed by calling getRepoThirdPartyPath()
+    **svn_kwargs: keyword arguments passed through to svn_helper.lsDirs()
+      (for "advanced users")
+
+  Returns:
+    A list of third-party packages found in pkg_path.  Third-party "packages"
+    are all of the directories is the pkg_path  directory (but not individual
+    files in pkg_path) that do *not* begin with an underscore (_).  Individual
+    files and directories beginning with underscores in the pkg_path directory
+    are omitted from the results.
   """
-  return [pkg for pkg in svn_helper.lsDirs(pkg_path, **kwargs)
+  return [pkg for pkg in svn_helper.lsDirs(pkg_path, **svn_kwargs)
             if not pkg.startswith('_')]
 
 
 def getRepoFrameworksPath(repo):
   """Returns path to Melange framework packages in the supplied svn repository.
+
+  Args:
+    repo: SVN repository URL
   """
-  return '%strunk/' % repo
+  # see note about directory names ending with / svn path separators in the
+  # module __doc__ string
+  return '%strunk/' % svn_helper.formatDirPath(repo)
 
 
 def getFrameworksNames():
-  """Returns a list of Melange framework packages (currently a static list).
+  """Returns a list of Melange framework packages (currently a constant list).
   """
+  # see note about directory names ending with / svn path separators in the
+  # module __doc__ string
   return ['soc/']
 
 
@@ -71,16 +160,41 @@
 
   Returns:
     * branch if it was specified ("non-False"), or
-    * users/user/dest if dest was specified, or
-    * users/user/src otherwise
+    * users/user/dest/ if dest was specified, or
+    * users/user/src/ otherwise
   """
   if not branch:
     if dest:
-      branch = 'users/%s%s' % (user, dest)
+      branch = 'users/%s%s' % (svn_helper.formatDirPath(user), dest)
     else:
-      branch = 'users/%s%s' % (user, src)
+      branch = 'users/%s%s' % (svn_helper.formatDirPath(user), src)
+
+  return svn_helper.formatDirPath(branch)
+
+
+def verbosePrint(verbose, fmt_str, *fmt_args, **fmt_kwargs):
+  """If verbosity level greater than zero, print out formatted string.
+
+  Since app_image.py is a utility module most often used by scripts, many
+  of its functions print to stdout.  For cases when printed output may not
+  be desired, functions should supply a 'verbose' parameter to disable
+  output.  The functions in app_image.py use this function to implement
+  that selective printing capability.
 
-  return branch
+  Args:
+    verbose: verbosity level integer, any value greater than 0 enables
+      output
+    fmt_str: required format string
+    *fmt_args: if present, positional arguments supplied to fmt_str
+    **fmt_kwargs: if *fmt_args is not present, named arguments supplied to
+      fmt_str, which is expected to contain named format specifiers, for
+      example: '%(foo)s'
+  """
+  if verbose > 0:
+    if not fmt_args:
+      fmt_args = fmt_kwargs
+
+    print fmt_str % fmt_args
 
 
 def branchFromSrcApp(app, repo, dest, verbose=1, **svn_kwargs):
@@ -95,8 +209,8 @@
   """
   repo_app = getRepoAppPath(repo, app)
 
-  if verbose > 0:
-    print 'Branching %s from:\n %s\nto:\n %s\n' % (app, repo_app, dest)
+  verbosePrint(verbose, 'Branching %s from:\n %s\nto:\n %s\n',
+               app, repo_app, dest)
 
   svn_helper.branchDir(repo_app, dest, **svn_kwargs)
 
@@ -119,9 +233,9 @@
   pkg_dir = getRepoThirdPartyPath(repo)
   packages = getThirdPartyPackageNames(pkg_dir)
 
-  if verbose > 0:
-    print 'Branching third-party packages:\n %s\nfrom:\n %s\ninto:\n %s\n' % (
-        '  '.join(packages), pkg_dir, dest)
+  verbosePrint(verbose,
+      'Branching third-party packages:\n %s\nfrom:\n %s\ninto:\n %s\n',
+      '  '.join(packages), pkg_dir, dest)
 
   svn_helper.branchItems(pkg_dir, dest, packages, **svn_kwargs)
 
@@ -140,8 +254,8 @@
   framework_dir = getRepoFrameworksPath(repo)
   packages = getFrameworksNames()
 
-  if verbose > 0:
-    print 'Branching framework components:\n %s\nfrom:\n %s\ninto:\n %s\n' % (
+  verbosePrint(verbose,
+      'Branching framework components:\n %s\nfrom:\n %s\ninto:\n %s\n',
       '  '.join(packages), framework_dir, dest)
 
   svn_helper.branchItems(framework_dir, dest, packages, **svn_kwargs)
@@ -159,8 +273,8 @@
   """
   repo_app = getRepoAppPath(repo, app)
 
-  if verbose > 0:
-    print 'Exporting %s from:\n %s\nto:\n %s\n' % (app, repo_app, dest)
+  verbosePrint(verbose, 'Exporting %s from:\n %s\nto:\n %s\n',
+               app, repo_app, dest)
 
   svn_helper.exportDir(repo_app, dest, **svn_kwargs)
 
@@ -183,9 +297,9 @@
   pkg_dir = getRepoThirdPartyPath(repo)
   packages = getThirdPartyPackageNames(pkg_dir)
 
-  if verbose > 0:
-    print 'Exporting third-party packages:\n %s\nfrom:\n %s\ninto:\n  %s\n' % (
-        '  '.join(packages), pkg_dir, dest)
+  verbosePrint(verbose,
+      'Exporting third-party packages:\n %s\nfrom:\n %s\ninto:\n  %s\n',
+      '  '.join(packages), pkg_dir, dest)
 
   svn_helper.exportItems(pkg_dir, dest, packages, **svn_kwargs)
 
@@ -204,8 +318,8 @@
   framework_dir = getRepoFrameworksPath(repo)
   packages = getFrameworksNames()
 
-  if verbose > 0:
-    print 'Exporting framework components:\n %s\nfrom:\n %s\ninto:\n %s\n' % (
-        '  '.join(packages), framework_dir, dest)
+  verbosePrint(verbose,
+      'Exporting framework components:\n %s\nfrom:\n %s\ninto:\n %s\n',
+      '  '.join(packages), framework_dir, dest)
 
   svn_helper.exportItems(framework_dir, dest, packages, **svn_kwargs)