]> scripts.mit.edu Git - wizard.git/commitdiff
More documentation improvements.
authorEdward Z. Yang <ezyang@mit.edu>
Mon, 16 Nov 2009 20:51:10 +0000 (15:51 -0500)
committerEdward Z. Yang <ezyang@mit.edu>
Mon, 16 Nov 2009 20:53:13 +0000 (15:53 -0500)
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
TODO
doc/conf.py
doc/index.rst
doc/module/wizard.app.php.rst [new file with mode: 0644]
doc/repository-conversion.rst
wizard/app/__init__.py
wizard/app/php.py
wizard/app/wordpress.py
wizard/install/__init__.py

diff --git a/TODO b/TODO
index dda76d0444a4450b047becb2a60ec25b809585fc..c55b94d04be4e6acb2a5f7d3dbf42fefe686b1aa 100644 (file)
--- a/TODO
+++ b/TODO
@@ -2,6 +2,7 @@ The Git Autoinstaller
 
 TODO NOW:
 
+- php.ini needs to get substituted!
 - Make wizard install accept appname-head (so that you can do a test with
   head, and do things without tags).  Also make it accept commit hashes.
   In fact, let it accept any committish.  Figure out what to do if we
@@ -48,6 +49,11 @@ TODO NOW:
       if merge resolutions aren't careful.  `php -l` can be a quick stopgap
 
 - Other stuff
+    - Figure out why Sphinx sometimes fails to crossref :func: but wil
+      crossref :meth:, even though the dest is very clearly a function.
+      Example: :func:`wizard.app.php.re_var`
+    - The TODO extension for Sphinx doesn't properly force a full-rebuild
+    - Code annotation!
     - Make single user mass-migrate work when not logged in as root
     - Don't use the scripts heuristics unless we're on scripts with the
       AFS patch.  Check with `fs sysname`
index 8a3a6a70163e78eb49a08b89977a5cfa14d6dca0..128f61a692d96dd178e57cd3dc92c4357616ecb9 100644 (file)
@@ -24,7 +24,14 @@ sys.path.append(os.path.abspath('..'))
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.doctest', 'sphinx.ext.graphviz']
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.coverage',
+    'sphinx.ext.doctest',
+    'sphinx.ext.graphviz',
+    'sphinx.ext.intersphinx',
+    'sphinx.ext.todo',
+    ]
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -197,3 +204,7 @@ latex_documents = [
 
 # If false, no module index is generated.
 #latex_use_modindex = True
+
+intersphinx_mapping = {'http://docs.python.org/dev': None}
+
+todo_include_todos = True
index 5da42e8fbf407efb33c287d5d591e3dc009fb087..71a50c762ce43ebb356c8148e7bc171f43695eb0 100644 (file)
@@ -65,6 +65,7 @@ Modules
 
     module/wizard
     module/wizard.app
+    module/wizard.app.php
     module/wizard.cache
     module/wizard.deploy
     module/wizard.install
diff --git a/doc/module/wizard.app.php.rst b/doc/module/wizard.app.php.rst
new file mode 100644 (file)
index 0000000..c46732d
--- /dev/null
@@ -0,0 +1,15 @@
+:mod:`wizard.app.php`
+=====================
+
+.. automodule:: wizard.app.php
+
+Functions
+---------
+.. autofunction:: re_var
+
+Data
+----
+.. autodata:: extractors
+.. autodata:: substitutions
+.. autodata:: parametrized_files
+.. autodata:: deprecated_keys
index 14a8547c6e35361719338dd4e0ce9d616cc0be2f..171f592db46ddcc70bf76a64d543d761cd2207ee 100644 (file)
@@ -1,6 +1,8 @@
 Repository conversion
 =====================
 
+.. highlight:: sh
+
 One of Wizard's goals is to replace the previous autoinstaller infrastructure.
 Pre-wizard autoinstalls live in :file:`/mit/scripts/deploy` and consist of a
 tarball from upstream, possibly a scripts patch, and possibly some post-install
@@ -19,8 +21,6 @@ an example.
 Setup
 -----
 
-.. highlight:: sh
-
 Probably the easiest way to do development is entirely on :term:`AFS`:  all
 of your source code should live in publically readable (i.e.
 ``system:anyuser`` as read permissions) directories, so that if you
@@ -70,8 +70,6 @@ named ``$WIZARD``; note that application repositories live in ``$WIZARD/srv``.
 Pristine
 --------
 
-.. highlight:: sh
-
 This is a tutorial centered around migrating `Wordpress <http://wordpress.org/>`_
 into our Git repository.  For the sake of demonstration,
 we shall assume that this repository hasn't been created yet.
@@ -82,17 +80,21 @@ The repository then doesn't exist, we should create it::
     cd wordpress
     git init
 
-.. highlight:: python
-
 We also have to create a module for the application, so we
-create ``$WIZARD/wizard/app/wordpress.py`` and fill it in with a bare bones template::
+create ``$WIZARD/wizard/app/wordpress.py`` and fill it in with a bare bones template:
+
+.. code-block:: python
+
+    import os
+    import re
+    import logging
+
+    from wizard import app, install, resolve, sql, util
+    from wizard.app import php
 
-    from wizard import app
     class Application(app.Application):
         pass
 
-.. highlight:: sh
-
 Now we are ready to put some code in our repository: the first thing we will
 add is the :term:`pristine` branch, which contains verbatim the code from upstream.
 If we were starting a new autoinstaller, we'd pop off and use the latest version,
@@ -108,17 +110,15 @@ Try running the following command in :file:`$WIZARD/srv/wordpress`::
 
     wizard prepare-pristine wordpress-2.0.2
 
-.. highlight:: python
-
 You should get an error complaining about :meth:`wizard.app.Application.download`
-not being implemented yet. Let's fix that::
+not being implemented yet. Let's fix that:
+
+.. code-block:: python
 
     class Application(app.Application):
         def download(self, version):
             return "http://wordpress.org/wordpress-%s.tar.gz" % version
 
-.. highlight:: sh
-
 We determined this by finding `Wordpress's Release Archive <http://wordpress.org/download/release-archive/>`_
 and inferring the naming scheme by inspecting various links.  You should now
 be able to run the prepare-pristine command successfully: when it is
@@ -202,8 +202,6 @@ are done, here is the graph from before, but augmented with the scripts versions
     c -> cs
     a []
 
-.. highlight:: sh
-
 First things first: verify that we are on the master branch::
 
     git checkout master
@@ -254,8 +252,14 @@ configuration file, so creating the install script involves:
 There's an in-depth explanation of named input values in
 :mod:`wizard.install`.  The short version is that your application
 contains a class-wide :data:`~wizard.app.Application.install_schema`
-attribute that encodes this information.  The constructor takes
-an arbitrary number of arguments (to be continued)
+attribute that encodes this information.  Instantiate it with
+:class:`wizard.install.ArgSchema` (passing in arguments to get
+some pre-canned input values), and then add application specific
+arguments by passing instances of :class:`wizard.install.Arg`
+to the method :meth:`~wizard.install.ArgSchema.add`.  Usually you should
+be able to get away with pre-canned attributes.  You can access
+these arguments inside :meth:`~wizard.app.Application.install` via
+the ``options`` value.
 
 Some tips and tricks for writing :meth:`wizard.app.Application.install`:
 
@@ -279,6 +283,11 @@ Some tips and tricks for writing :meth:`wizard.app.Application.install`:
       consequently be queried.  For convenience, we've bound metadata
       to the connection, you can perform implicit execution.
 
+.. todo::
+
+    Our installer needs to also parametrize :file:`php.ini`, which we haven't
+    done yet.
+
 To test if your installation function works, it's probably convenient to
 create a test script in :file:`tests`; :file:`tests/test-install-wordpress.sh`
 in the case of Wordpress.  It will look something like::
@@ -295,6 +304,97 @@ in the case of Wordpress.  It will look something like::
 operation without any version specified (since we haven't tagged any of our
 commits yet, we can't use the specific version functionality; not that we'd want
 to, though).  ``TESTNAME`` is simply the name of the file with the leading
-``test-`` stripped and dashes converted to underscores.
+``test-`` stripped and dashes converted to underscores.  Run the script with
+verbose debugging information by using::
+
+    env WIZARD_DEBUG=1 ./test-install-wordpress.sh
+
+Versioning config
+-----------------
+
+A design decision that was made early on during Wizard's development was that
+the scriptsified versions would contain generic copies of the configuration
+files.  You're going to generate this generic copy now and in doing so,
+overload your previous scripts commit.   Because some installers
+exhibit different behavior depending on server configuration, you should run
+the installation on a Scripts server::
+
+    wizard install wordpress --no-commit
+
+The installer will interactively prompt you for some values, and then conclude
+the install.  ``--no-commit`` prevents the installer from generating a Git
+commit after the install, and will make it easier for us to propagate the
+change back to the parent repository.
+
+Look at the changes the installer made::
+
+    git status
+
+There are probably now a few unversioned files lounging around; these are probably
+the configuration files that the installer generated.
+
+You will now need to implement the following data attributes and methods in your
+:class:`~wizard.app.Application` class: :attr:`~wizard.app.Application.extractors`,
+:attr:`~wizard.app.Application.substitutions`, :attr:`~wizard.app.Application.parametrized_files`,
+:meth:`~wizard.app.Application.checkConfig` and :meth:`~wizard.app.Application.detectVersion`.
+These are all closely related to the configuration files that the installer generated.
+
+:meth:`~wizard.app.Application.checkConfig` is the most straightforward method to
+write: you will usually only need to test for the existence of the configuration file.
+Note that this function will always be called with the current working directory being
+the deployment, so you can simplify your code accordingly:
+
+.. code-block:: python
+
+    def checkConfig(self, deployment):
+        return os.path.isfile("wp-config.php")
+
+:meth:`~wizard.app.Application.detectVersion` should detect the version of the application
+by regexing it out of a source file.  We first have to figure out where the version number
+is stored: a quick grep tells us that it's in :file:`wp-includes/version.php`:
+
+.. code-block:: php
+
+    <?php
+
+    // This just holds the version number, in a separate file so we can bump it without cluttering the SVN
+
+    $wp_version = '2.0.4';
+    $wp_db_version = 3440;
+
+    ?>
+
+We could now grab the :mod:`re` module and start constructing a regex to grab ``2.0.4``, but it
+turns out this isn't necessary: :meth:`wizard.app.php.re_var` does this for us already!
+If such a module doesn't exist, you should create it and place an equivalent ``re_var()``
+function for that language there.
+
+With this function in hand, writing a version detection function is pretty straightforward.
+There is one gotcha: the value that ``re_var`` returns as the second subpattern is quoted (the reasons for this
+will become clear shortly), so you will need to trim off the last and first characters or
+use :mod:`shlex`.  In the case of version numbers, there are probably no escape characters
+in the string, so the former is relatively safe.
+
+.. code-block:: python
+
+    def detectVersion(self, deployment):
+        contents = open("wp-includes/version.php").read()
+        match = php.re_var("wp_version").search(contents)
+        if not match: return None
+        return distutils.version.LooseVersion(match.group(2)[1:-1])
+
+:attr:`~wizard.app.Application.parametrized_files` is a simple list of files that the
+program's installer wrote or touched during the installation process.
+
+.. code-block:: python
+
+    parametrized_files = ['wp-config.php']
+
+This is actually is a lie: we also need to include changes to :file:`php.ini` that
+we made:
+
+.. code-block:: python
+
+    parametrized_files = ['wp-config.php'] + php.parametrized_files
+
 
-(to be continued)
index 929cacfb35c66715e3ba2999da46cafaf875e243..0e6bd1aac76c440f0e0e0f3b2c9bd9ac069f5984 100644 (file)
@@ -6,6 +6,11 @@ You'll need to know how to overload the :class:`Application` class
 and use some of the functions in this module in order to specify
 new applications.
 
+There are some submodules for programming languages that define common
+functions and data that may be used by applications in that language.  See:
+
+* :mod:`wizard.app.php`
+
 .. testsetup:: *
 
     import re
@@ -364,7 +369,7 @@ def expand_re(val):
 
 def make_extractors(seed):
     """
-    Take a dictionary of ``key``s to ``(file, regex)`` tuples and convert them into
+    Take a dictionary of ``key`` to ``(file, regex)`` tuples and convert them into
     extractor functions (which take a :class:`wizard.deploy.Deployment`
     and return the value of the second subpattern of ``regex`` when matched
     with the contents of ``file``).
@@ -373,7 +378,7 @@ def make_extractors(seed):
 
 def make_substitutions(seed):
     """
-    Take a dictionary of ``key``s to ``(file, regex)`` tuples and convert them into substitution
+    Take a dictionary of ``key`` to ``(file, regex)`` tuples and convert them into substitution
     functions (which take a :class:`wizard.deploy.Deployment`, replace the second subpattern
     of ``regex`` with ``key`` in ``file``, and returns the number of substitutions made.)
     """
index ec5bdeee7b7686797d330a66570c31690d7e3813..a049716326ba58ec23e87f735c05cdfda2c6d5c3 100644 (file)
@@ -1,19 +1,39 @@
+"""
+Common data and functions for use in PHP applications.
+
+.. testsetup:: *
+
+    from wizard.app.php import *
+"""
+
 import re
 
 from wizard import app, util
 
 def re_var(var):
+    """
+    Generates a regexp for assignment to ``var`` in PHP; the quoted
+    value is the second subpattern.
+
+    >>> re_var('key').search("$key = 'val';").group(2)
+    "'val'"
+    """
     return re.compile('^(\$' + app.expand_re(var) + r'''\s*=\s*)(.*)(;)''', re.M)
 
-def make_filename_regex(var):
+def _make_filename_regex(var):
     return 'php.ini', re.compile('^(' + app.expand_re(var) + r'\s*=\s*)(.*)()$', re.M)
 
-seed = util.dictmap(make_filename_regex, {
+seed = util.dictmap(_make_filename_regex, {
         'WIZARD_SESSIONNAME': 'session.name',
         'WIZARD_TMPDIR': ('upload_tmp_dir', 'session.save_path'),
         })
 
+#: Common extractors for parameters in :file:`php.ini`.
 extractors = app.make_extractors(seed)
+#: Common substitutions for parameters in :file:`php.ini`.
 substitutions = app.make_substitutions(seed)
+#: A list containing :file:`php.ini`.
+parametrized_files = ["php.ini"]
+#: Nop for consistency.
 deprecated_keys = set([])
 
index fc83818d5dc85db72f71bd2af106127b5c60fc79..9bc112fd60798d90a2bbf959f62933c5014fcc19 100644 (file)
@@ -20,8 +20,7 @@ seed = util.dictmap(make_filename_regex_define, {
 # arbitrary table prefixes this should be added.
 
 class Application(app.Application):
-    # XXX: php.ini should be grabbed over from the php module
-    parametrized_files = ['wp-config.php', 'php.ini']
+    parametrized_files = ['wp-config.php'] + php.parametrized_files
     extractors = app.make_extractors(seed)
     extractors.update(php.extractors)
     substitutions = app.make_substitutions(seed)
index 87ade20e0c557aad1c94aa75747780b9fbb84562..609c02c0d47b3885ea06faefd1df3389a989f6a6 100644 (file)
@@ -257,6 +257,7 @@ class ArgSchema(object):
     * ``admin``, which populates the options ``admin_name`` and
       ``admin_password``.
     * ``email``, which populates the option ``email``.
+    * ``title``, which populates the option ``title``.
 
     The options ``web_path`` and ``web_host`` are automatically required.