scripts/app_image.py
changeset 48 39e1c8a54b37
parent 45 66c450a53786
equal deleted inserted replaced
47:a237c3c5763e 48:39e1c8a54b37
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14 # See the License for the specific language governing permissions and
    14 # See the License for the specific language governing permissions and
    15 # limitations under the License.
    15 # limitations under the License.
    16 
    16 
    17 """Functions used by multiple scripts to form Google App Engine images.
    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.
    18 """
    73 """
    19 
    74 
    20 __authors__ = [
    75 __authors__ = [
    21   # alphabetical order by last name, please
    76   # alphabetical order by last name, please
    22   '"Todd Larsen" <tlarsen@google.com>',
    77   '"Todd Larsen" <tlarsen@google.com>',
    23 ]
    78 ]
    24 
    79 
    25 
    80 
       
    81 import sys
       
    82 
    26 from trunk.scripts import svn_helper
    83 from trunk.scripts import svn_helper
    27 
    84 
    28 
    85 
    29 def getRepoAppPath(repo, app):
    86 def getRepoAppPath(repo, app):
    30   """Returns path to specified Melange app in the supplied svn repository.
    87   """Returns path to specified Melange app in the supplied svn repository.
    31   """
    88 
    32   return '%strunk/apps/%s' % (repo, app)
    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))
    33 
    97 
    34 
    98 
    35 def getRepoThirdPartyPath(repo):
    99 def getRepoThirdPartyPath(repo):
    36   """Returns path to third-party packages in the supplied svn repository.
   100   """Returns path to third-party packages in the supplied svn repository.
    37   """
   101 
    38   return '%sthirdparty/' % repo
   102   Args:
    39 
   103     repo: SVN repository URL
    40 
   104   """
    41 def getThirdPartyPackageNames(pkg_path, **kwargs):
   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):
    42   """Returns a list of third-party packages in the supplied URL.
   111   """Returns a list of third-party packages in the supplied URL.
    43   """
   112 
    44   return [pkg for pkg in svn_helper.lsDirs(pkg_path, **kwargs)
   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)
    45             if not pkg.startswith('_')]
   127             if not pkg.startswith('_')]
    46 
   128 
    47 
   129 
    48 def getRepoFrameworksPath(repo):
   130 def getRepoFrameworksPath(repo):
    49   """Returns path to Melange framework packages in the supplied svn repository.
   131   """Returns path to Melange framework packages in the supplied svn repository.
    50   """
   132 
    51   return '%strunk/' % repo
   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)
    52 
   139 
    53 
   140 
    54 def getFrameworksNames():
   141 def getFrameworksNames():
    55   """Returns a list of Melange framework packages (currently a static list).
   142   """Returns a list of Melange framework packages (currently a constant list).
    56   """
   143   """
       
   144   # see note about directory names ending with / svn path separators in the
       
   145   # module __doc__ string
    57   return ['soc/']
   146   return ['soc/']
    58 
   147 
    59 
   148 
    60 def formDefaultAppBranchPath(branch, user, src, dest):
   149 def formDefaultAppBranchPath(branch, user, src, dest):
    61   """Returns a relative path to a to-be-created App Image branch.
   150   """Returns a relative path to a to-be-created App Image branch.
    69       in its new, branched location, if it was specified (or None, '', etc.
   158       in its new, branched location, if it was specified (or None, '', etc.
    70       instead, if it was not)
   159       instead, if it was not)
    71 
   160 
    72   Returns:
   161   Returns:
    73     * branch if it was specified ("non-False"), or
   162     * branch if it was specified ("non-False"), or
    74     * users/user/dest if dest was specified, or
   163     * users/user/dest/ if dest was specified, or
    75     * users/user/src otherwise
   164     * users/user/src/ otherwise
    76   """
   165   """
    77   if not branch:
   166   if not branch:
    78     if dest:
   167     if dest:
    79       branch = 'users/%s%s' % (user, dest)
   168       branch = 'users/%s%s' % (svn_helper.formatDirPath(user), dest)
    80     else:
   169     else:
    81       branch = 'users/%s%s' % (user, src)
   170       branch = 'users/%s%s' % (svn_helper.formatDirPath(user), src)
    82 
   171 
    83   return branch
   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
    84 
   198 
    85 
   199 
    86 def branchFromSrcApp(app, repo, dest, verbose=1, **svn_kwargs):
   200 def branchFromSrcApp(app, repo, dest, verbose=1, **svn_kwargs):
    87   """Branch one Melange app in /trunk/apps/ to form basis of App Engine image.
   201   """Branch one Melange app in /trunk/apps/ to form basis of App Engine image.
    88 
   202 
    93     verbose: print status if greater than 0; default is 1
   207     verbose: print status if greater than 0; default is 1
    94     **svn_kwargs: keyword arguments passed on to svn_helper.branchDir()
   208     **svn_kwargs: keyword arguments passed on to svn_helper.branchDir()
    95   """
   209   """
    96   repo_app = getRepoAppPath(repo, app)
   210   repo_app = getRepoAppPath(repo, app)
    97 
   211 
    98   if verbose > 0:
   212   verbosePrint(verbose, 'Branching %s from:\n %s\nto:\n %s\n',
    99     print 'Branching %s from:\n %s\nto:\n %s\n' % (app, repo_app, dest)
   213                app, repo_app, dest)
   100 
   214 
   101   svn_helper.branchDir(repo_app, dest, **svn_kwargs)
   215   svn_helper.branchDir(repo_app, dest, **svn_kwargs)
   102 
   216 
   103 
   217 
   104 def branchFromThirdParty(repo, dest, verbose=1, **svn_kwargs):
   218 def branchFromThirdParty(repo, dest, verbose=1, **svn_kwargs):
   117     **svn_kwargs: keyword arguments passed on to svn_helper.branchItems()
   231     **svn_kwargs: keyword arguments passed on to svn_helper.branchItems()
   118   """
   232   """
   119   pkg_dir = getRepoThirdPartyPath(repo)
   233   pkg_dir = getRepoThirdPartyPath(repo)
   120   packages = getThirdPartyPackageNames(pkg_dir)
   234   packages = getThirdPartyPackageNames(pkg_dir)
   121 
   235 
   122   if verbose > 0:
   236   verbosePrint(verbose,
   123     print 'Branching third-party packages:\n %s\nfrom:\n %s\ninto:\n %s\n' % (
   237       'Branching third-party packages:\n %s\nfrom:\n %s\ninto:\n %s\n',
   124         '  '.join(packages), pkg_dir, dest)
   238       '  '.join(packages), pkg_dir, dest)
   125 
   239 
   126   svn_helper.branchItems(pkg_dir, dest, packages, **svn_kwargs)
   240   svn_helper.branchItems(pkg_dir, dest, packages, **svn_kwargs)
   127 
   241 
   128 
   242 
   129 def branchFromFramework(repo, dest, verbose=1, **svn_kwargs):
   243 def branchFromFramework(repo, dest, verbose=1, **svn_kwargs):
   138     **svn_kwargs: keyword arguments passed on to svn_helper.branchItems()
   252     **svn_kwargs: keyword arguments passed on to svn_helper.branchItems()
   139   """
   253   """
   140   framework_dir = getRepoFrameworksPath(repo)
   254   framework_dir = getRepoFrameworksPath(repo)
   141   packages = getFrameworksNames()
   255   packages = getFrameworksNames()
   142 
   256 
   143   if verbose > 0:
   257   verbosePrint(verbose,
   144     print 'Branching framework components:\n %s\nfrom:\n %s\ninto:\n %s\n' % (
   258       'Branching framework components:\n %s\nfrom:\n %s\ninto:\n %s\n',
   145       '  '.join(packages), framework_dir, dest)
   259       '  '.join(packages), framework_dir, dest)
   146 
   260 
   147   svn_helper.branchItems(framework_dir, dest, packages, **svn_kwargs)
   261   svn_helper.branchItems(framework_dir, dest, packages, **svn_kwargs)
   148 
   262 
   149 
   263 
   157     verbose: print status if greater than 0; default is 1
   271     verbose: print status if greater than 0; default is 1
   158     **svn_kwargs: keyword arguments passed on to svn_helper.exportDir()
   272     **svn_kwargs: keyword arguments passed on to svn_helper.exportDir()
   159   """
   273   """
   160   repo_app = getRepoAppPath(repo, app)
   274   repo_app = getRepoAppPath(repo, app)
   161 
   275 
   162   if verbose > 0:
   276   verbosePrint(verbose, 'Exporting %s from:\n %s\nto:\n %s\n',
   163     print 'Exporting %s from:\n %s\nto:\n %s\n' % (app, repo_app, dest)
   277                app, repo_app, dest)
   164 
   278 
   165   svn_helper.exportDir(repo_app, dest, **svn_kwargs)
   279   svn_helper.exportDir(repo_app, dest, **svn_kwargs)
   166 
   280 
   167 
   281 
   168 def exportFromThirdParty(repo, dest, verbose=1, **svn_kwargs):
   282 def exportFromThirdParty(repo, dest, verbose=1, **svn_kwargs):
   181     **svn_kwargs: keyword arguments passed on to svn_helper.exportItems()
   295     **svn_kwargs: keyword arguments passed on to svn_helper.exportItems()
   182   """
   296   """
   183   pkg_dir = getRepoThirdPartyPath(repo)
   297   pkg_dir = getRepoThirdPartyPath(repo)
   184   packages = getThirdPartyPackageNames(pkg_dir)
   298   packages = getThirdPartyPackageNames(pkg_dir)
   185 
   299 
   186   if verbose > 0:
   300   verbosePrint(verbose,
   187     print 'Exporting third-party packages:\n %s\nfrom:\n %s\ninto:\n  %s\n' % (
   301       'Exporting third-party packages:\n %s\nfrom:\n %s\ninto:\n  %s\n',
   188         '  '.join(packages), pkg_dir, dest)
   302       '  '.join(packages), pkg_dir, dest)
   189 
   303 
   190   svn_helper.exportItems(pkg_dir, dest, packages, **svn_kwargs)
   304   svn_helper.exportItems(pkg_dir, dest, packages, **svn_kwargs)
   191 
   305 
   192 
   306 
   193 def exportFromFramework(repo, dest, verbose=1, **svn_kwargs):
   307 def exportFromFramework(repo, dest, verbose=1, **svn_kwargs):
   202     **svn_kwargs: keyword arguments passed on to svn_helper.exportItems()
   316     **svn_kwargs: keyword arguments passed on to svn_helper.exportItems()
   203   """
   317   """
   204   framework_dir = getRepoFrameworksPath(repo)
   318   framework_dir = getRepoFrameworksPath(repo)
   205   packages = getFrameworksNames()
   319   packages = getFrameworksNames()
   206 
   320 
   207   if verbose > 0:
   321   verbosePrint(verbose,
   208     print 'Exporting framework components:\n %s\nfrom:\n %s\ninto:\n %s\n' % (
   322       'Exporting framework components:\n %s\nfrom:\n %s\ninto:\n %s\n',
   209         '  '.join(packages), framework_dir, dest)
   323       '  '.join(packages), framework_dir, dest)
   210 
   324 
   211   svn_helper.exportItems(framework_dir, dest, packages, **svn_kwargs)
   325   svn_helper.exportItems(framework_dir, dest, packages, **svn_kwargs)