scripts/app_image.py
changeset 105 b7a32c7e2a99
parent 104 5a2786fd5048
child 106 667451541623
equal deleted inserted replaced
104:5a2786fd5048 105:b7a32c7e2a99
     1 #!/usr/bin/python2.5
       
     2 #
       
     3 # Copyright 2008 the Melange authors.
       
     4 #
       
     5 # Licensed under the Apache License, Version 2.0 (the "License");
       
     6 # you may not use this file except in compliance with the License.
       
     7 # You may obtain a copy of the License at
       
     8 #
       
     9 #   http://www.apache.org/licenses/LICENSE-2.0
       
    10 #
       
    11 # Unless required by applicable law or agreed to in writing, software
       
    12 # distributed under the License is distributed on an "AS IS" BASIS,
       
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    14 # See the License for the specific language governing permissions and
       
    15 # limitations under the License.
       
    16 
       
    17 """Functions used by multiple scripts to form Google App Engine images.
       
    18 
       
    19 These utility functions are used by multiple scripts for creating and managing
       
    20 Google App Engine "uploadable image" directories produced by combining a
       
    21 specific Melange application (for example: trunk/apps/proto, trunk/apps/gsoc,
       
    22 trunk/apps/ghop, etc.), the SoC framework in trunk/soc, and any /thirdparty/
       
    23 packages, such as thirdparty/django.
       
    24 
       
    25 The directory layout expected by Google App Engine is (approximately):
       
    26   <app>/
       
    27         app.yaml
       
    28         index.yaml
       
    29         content/     (a static content directory for the Melange application)
       
    30         main.py      (a WSGI wrapper for Django-based Google App Engine apps)
       
    31         settings.py  (application-specific Django settings)
       
    32         urls.py      (application-specific URL handler mappings)
       
    33 
       
    34 The application itself can have application-specific code and templates, so
       
    35 there is an additional subdirectory with the same name as the application
       
    36 (to disambiguate modules in the Melange application with same-named modules
       
    37 in the SoC framework):
       
    38   <app>/
       
    39         <app>/
       
    40               models/, templates/, views/, etc.
       
    41 
       
    42 Google App Engine assumes that the root of package paths is <app>/, so all
       
    43 packages are placed in sub-directories of <app>/, and the SoC framework
       
    44 is considered a package:
       
    45   <app>/
       
    46         soc/
       
    47             models/, templates/, views/, etc.
       
    48 
       
    49 For Django template based applications (which Melange applications are),
       
    50 include the django distribution directory (which is one of the /thirdparty/
       
    51 packages) and some Django-specific files:
       
    52   <app>/
       
    53         django/
       
    54                core/, db/, dispatch/, etc.
       
    55 
       
    56 Any other /thirdparty/ packages would be included in the the Google App Engine
       
    57 "uploadable image" directory similarly to Django above.
       
    58 
       
    59 
       
    60 A NOTE ABOUT DIRECTORY NAMES RETURNED BY FUNCTIONS IN THIS MODULE
       
    61 
       
    62 The functions in this module return directory names with a trailing / svn path
       
    63 separator.  This is done by convention only (svn_helper functions normalize
       
    64 the path names of directories in this same way).  The trailing separator is
       
    65 kept to make it easier to combine paths (since the caller can always assume
       
    66 directories end with the / separator) and to make it easier to distinguish
       
    67 directories from files in human-readable output.
       
    68 
       
    69 Some pysvn Client methods accept directories named this way, others raise
       
    70 exceptions and expect a "canonical" form that does not include the trailing
       
    71 / separator.  This does not seem to be documented in the pysvn documentation,
       
    72 so the trailing separator is removed in svn_helper when necessary.
       
    73 """
       
    74 
       
    75 __authors__ = [
       
    76   # alphabetical order by last name, please
       
    77   '"Todd Larsen" <tlarsen@google.com>',
       
    78 ]
       
    79 
       
    80 
       
    81 import sys
       
    82 
       
    83 from trunk.scripts import svn_helper
       
    84 
       
    85 
       
    86 def getRepoAppPath(repo, app):
       
    87   """Returns path to specified Melange app in the supplied svn repository.
       
    88 
       
    89   Args:
       
    90     repo: SVN repository URL
       
    91     app: Melange application name (expected to exist in trunk/apps)
       
    92   """
       
    93   # see note about directory names ending with / svn path separators in the
       
    94   # module __doc__ string
       
    95   return svn_helper.formatDirPath('%strunk/apps/%s' % (
       
    96       svn_helper.formatDirPath(repo), app))
       
    97 
       
    98 
       
    99 def getRepoThirdPartyPath(repo):
       
   100   """Returns path to third-party packages in the supplied svn repository.
       
   101 
       
   102   Args:
       
   103     repo: SVN repository URL
       
   104   """
       
   105   # see note about directory names ending with / svn path separators in the
       
   106   # module __doc__ string
       
   107   return '%sthirdparty/' % svn_helper.formatDirPath(repo)
       
   108 
       
   109 
       
   110 def getThirdPartyPackageNames(pkg_path, **svn_kwargs):
       
   111   """Returns a list of third-party packages in the supplied URL.
       
   112 
       
   113   Args:
       
   114     pkg_path: full SVN URL path to the directory containing third-party
       
   115       packages, usually the path formed by calling getRepoThirdPartyPath()
       
   116     **svn_kwargs: keyword arguments passed through to svn_helper.lsDirs()
       
   117       (for "advanced users")
       
   118 
       
   119   Returns:
       
   120     A list of third-party packages found in pkg_path.  Third-party "packages"
       
   121     are all of the directories is the pkg_path  directory (but not individual
       
   122     files in pkg_path) that do *not* begin with an underscore (_).  Individual
       
   123     files and directories beginning with underscores in the pkg_path directory
       
   124     are omitted from the results.
       
   125   """
       
   126   return [pkg for pkg in svn_helper.lsDirs(pkg_path, **svn_kwargs)
       
   127             if not pkg.startswith('_')]
       
   128 
       
   129 
       
   130 def getRepoFrameworksPath(repo):
       
   131   """Returns path to Melange framework packages in the supplied svn repository.
       
   132 
       
   133   Args:
       
   134     repo: SVN repository URL
       
   135   """
       
   136   # see note about directory names ending with / svn path separators in the
       
   137   # module __doc__ string
       
   138   return '%strunk/' % svn_helper.formatDirPath(repo)
       
   139 
       
   140 
       
   141 def getFrameworksNames():
       
   142   """Returns a list of Melange framework packages (currently a constant list).
       
   143   """
       
   144   # see note about directory names ending with / svn path separators in the
       
   145   # module __doc__ string
       
   146   return ['soc/']
       
   147 
       
   148 
       
   149 def formDefaultAppBranchPath(branch, user, src, dest):
       
   150   """Returns a relative path to a to-be-created App Image branch.
       
   151 
       
   152   Args:
       
   153     branch: explicit branch name, if it was specified (or None, '', etc.
       
   154       instead, if it was not)
       
   155     user: subdirectory of /users/ representing a particular contributor
       
   156     src: sub-directory name of the specific Melange application to branch
       
   157     dest: alternate destination sub-directory name of the Melange application
       
   158       in its new, branched location, if it was specified (or None, '', etc.
       
   159       instead, if it was not)
       
   160 
       
   161   Returns:
       
   162     * branch if it was specified ("non-False"), or
       
   163     * users/user/dest/ if dest was specified, or
       
   164     * users/user/src/ otherwise
       
   165   """
       
   166   if not branch:
       
   167     if dest:
       
   168       branch = 'users/%s%s' % (svn_helper.formatDirPath(user), dest)
       
   169     else:
       
   170       branch = 'users/%s%s' % (svn_helper.formatDirPath(user), src)
       
   171 
       
   172   return svn_helper.formatDirPath(branch)
       
   173 
       
   174 
       
   175 def verbosePrint(verbose, fmt_str, *fmt_args, **fmt_kwargs):
       
   176   """If verbosity level greater than zero, print out formatted string.
       
   177 
       
   178   Since app_image.py is a utility module most often used by scripts, many
       
   179   of its functions print to stdout.  For cases when printed output may not
       
   180   be desired, functions should supply a 'verbose' parameter to disable
       
   181   output.  The functions in app_image.py use this function to implement
       
   182   that selective printing capability.
       
   183 
       
   184   Args:
       
   185     verbose: verbosity level integer, any value greater than 0 enables
       
   186       output
       
   187     fmt_str: required format string
       
   188     *fmt_args: if present, positional arguments supplied to fmt_str
       
   189     **fmt_kwargs: if *fmt_args is not present, named arguments supplied to
       
   190       fmt_str, which is expected to contain named format specifiers, for
       
   191       example: '%(foo)s'
       
   192   """
       
   193   if verbose > 0:
       
   194     if not fmt_args:
       
   195       fmt_args = fmt_kwargs
       
   196 
       
   197     print fmt_str % fmt_args
       
   198 
       
   199 
       
   200 def branchFromSrcApp(app, repo, dest, verbose=1, **svn_kwargs):
       
   201   """Branch one Melange app in /trunk/apps/ to form basis of App Engine image.
       
   202 
       
   203   Args:
       
   204     app: Melange application name in /trunk/apps/
       
   205     repo: svn repository root URL
       
   206     dest: working copy destination path of the image branch
       
   207     verbose: print status if greater than 0; default is 1
       
   208     **svn_kwargs: keyword arguments passed on to svn_helper.branchDir()
       
   209   """
       
   210   repo_app = getRepoAppPath(repo, app)
       
   211 
       
   212   verbosePrint(verbose, 'Branching %s from:\n %s\nto:\n %s\n',
       
   213                app, repo_app, dest)
       
   214 
       
   215   svn_helper.branchDir(repo_app, dest, **svn_kwargs)
       
   216 
       
   217 
       
   218 def branchFromThirdParty(repo, dest, verbose=1, **svn_kwargs):
       
   219   """Branch all subdirectories in /thirdparty/ into a new App Engine image.
       
   220 
       
   221   Subdirectories (except for those with names beginning with underscores) in
       
   222   /thirdparty/ represent third-party packages that are to be placed in each
       
   223   Google App Engine "image" branch.  Files in the root of /thirdparty/ (that
       
   224   is, not in a package) and, as previously mentioned, subdrectories beginning
       
   225   with underscores, are *not* branched.
       
   226 
       
   227   Args:
       
   228     repo: svn repository root URL
       
   229     dest: working copy destination path of the image branch
       
   230     verbose: print status if greater than 0; default is 1
       
   231     **svn_kwargs: keyword arguments passed on to svn_helper.branchItems()
       
   232   """
       
   233   pkg_dir = getRepoThirdPartyPath(repo)
       
   234   packages = getThirdPartyPackageNames(pkg_dir)
       
   235 
       
   236   verbosePrint(verbose,
       
   237       'Branching third-party packages:\n %s\nfrom:\n %s\ninto:\n %s\n',
       
   238       '  '.join(packages), pkg_dir, dest)
       
   239 
       
   240   svn_helper.branchItems(pkg_dir, dest, packages, **svn_kwargs)
       
   241 
       
   242 
       
   243 def branchFromFramework(repo, dest, verbose=1, **svn_kwargs):
       
   244   """Branch the SoC framework into a new App Engine image branch.
       
   245 
       
   246   The SoC framework current consists of only the contents of /trunk/soc/.
       
   247 
       
   248   Args:
       
   249     repo: svn repository root URL
       
   250     dest: working copy destination path of the image branch
       
   251     verbose: print status if greater than 0; default is 1
       
   252     **svn_kwargs: keyword arguments passed on to svn_helper.branchItems()
       
   253   """
       
   254   framework_dir = getRepoFrameworksPath(repo)
       
   255   packages = getFrameworksNames()
       
   256 
       
   257   verbosePrint(verbose,
       
   258       'Branching framework components:\n %s\nfrom:\n %s\ninto:\n %s\n',
       
   259       '  '.join(packages), framework_dir, dest)
       
   260 
       
   261   svn_helper.branchItems(framework_dir, dest, packages, **svn_kwargs)
       
   262 
       
   263 
       
   264 def exportFromSrcApp(app, repo, dest, verbose=1, **svn_kwargs):
       
   265   """Export one Melange app in /trunk/apps/ to form basis of App Engine image.
       
   266 
       
   267   Args:
       
   268     app: Melange application name in /trunk/apps/
       
   269     repo: svn repository root URL
       
   270     dest: local filesystem destination path of the exported image
       
   271     verbose: print status if greater than 0; default is 1
       
   272     **svn_kwargs: keyword arguments passed on to svn_helper.exportDir()
       
   273   """
       
   274   repo_app = getRepoAppPath(repo, app)
       
   275 
       
   276   verbosePrint(verbose, 'Exporting %s from:\n %s\nto:\n %s\n',
       
   277                app, repo_app, dest)
       
   278 
       
   279   svn_helper.exportDir(repo_app, dest, **svn_kwargs)
       
   280 
       
   281 
       
   282 def exportFromThirdParty(repo, dest, verbose=1, **svn_kwargs):
       
   283   """Export all subdirectories in /thirdparty/ into a new App Engine image.
       
   284 
       
   285   Subdirectories (except for those with names beginning with underscores) in
       
   286   /thirdparty/ represent third-party packages that are to be placed in each
       
   287   Google App Engine "image".  Files in the root of /thirdparty/ (that is,
       
   288   not in a package) and, as previously mentioned, subdirectories beginning
       
   289   with underscores, are *not* exported.
       
   290 
       
   291   Args:
       
   292     repo: svn repository root URL
       
   293     dest: local filesystem destination path of the exported image
       
   294     verbose: print status if greater than 0; default is 1
       
   295     **svn_kwargs: keyword arguments passed on to svn_helper.exportItems()
       
   296   """
       
   297   pkg_dir = getRepoThirdPartyPath(repo)
       
   298   packages = getThirdPartyPackageNames(pkg_dir)
       
   299 
       
   300   verbosePrint(verbose,
       
   301       'Exporting third-party packages:\n %s\nfrom:\n %s\ninto:\n  %s\n',
       
   302       '  '.join(packages), pkg_dir, dest)
       
   303 
       
   304   svn_helper.exportItems(pkg_dir, dest, packages, **svn_kwargs)
       
   305 
       
   306 
       
   307 def exportFromFramework(repo, dest, verbose=1, **svn_kwargs):
       
   308   """Export the SoC framework into a new App Engine image.
       
   309 
       
   310   The SoC framework current consists of only the contents of /trunk/soc/.
       
   311 
       
   312   Args:
       
   313     repo: svn repository root URL
       
   314     dest: local filesystem destination path of the exported image
       
   315     verbose: print status if greater than 0; default is 1
       
   316     **svn_kwargs: keyword arguments passed on to svn_helper.exportItems()
       
   317   """
       
   318   framework_dir = getRepoFrameworksPath(repo)
       
   319   packages = getFrameworksNames()
       
   320 
       
   321   verbosePrint(verbose,
       
   322       'Exporting framework components:\n %s\nfrom:\n %s\ninto:\n %s\n',
       
   323       '  '.join(packages), framework_dir, dest)
       
   324 
       
   325   svn_helper.exportItems(framework_dir, dest, packages, **svn_kwargs)