From: Edward Z. Yang Date: Sat, 14 Nov 2009 08:17:31 +0000 (-0500) Subject: Expand documentation. X-Git-Url: https://scripts.mit.edu/gitweb/wizard.git/commitdiff_plain/7b2533e1821daeb667b60c00dda4fd7d4ad3c41e Expand documentation. Signed-off-by: Edward Z. Yang --- diff --git a/doc/conf.py b/doc/conf.py index f477c2e..8a3a6a7 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -24,7 +24,7 @@ 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'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.doctest', 'sphinx.ext.graphviz'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/doc/repository-conversion.rst b/doc/repository-conversion.rst index bb5c5b1..14a8547 100644 --- a/doc/repository-conversion.rst +++ b/doc/repository-conversion.rst @@ -108,6 +108,193 @@ Try running the following command in :file:`$WIZARD/srv/wordpress`:: wizard prepare-pristine wordpress-2.0.2 -You should get an error complaining about :func:`wizard.app.Application.download` not being implemented yet. +.. highlight:: python + +You should get an error complaining about :meth:`wizard.app.Application.download` +not being implemented yet. Let's fix that:: + + 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 `_ +and inferring the naming scheme by inspecting various links. You should now +be able to run the prepare-pristine command successfully: when it is +done, you'll now have a bunch of files in your repository, and they +will be ready to be committed. Inspect the files and commit (note that the +format of the commit message is a plain Appname Version.Number):: + + git status + git commit -asm "Wordpress 2.0.2" + git tag wordpress-2.0.2 + +.. note:: + + Sometimes, ``http://wordpress.org/wordpress-2.0.2.tar.gz`` won't + actually exist anymore (it didn't exist when we did it). In this case, + you'll probably be able to find the original tarball in + :file:`/mit/scripts/deploy/wordpress-2.0.2`, and you can feed it + manually to prepare pristine with + ``wizard prepare-pristine /mit/scripts/deploy/wordpress-2.0.2/wordpress-2.0.2.tar.gz`` + +Some last house-keeping bits: now that you have a commit in a repository, you +can also create a pristine branch:: + + git branch pristine + +From the point of view of the pristine branch pointer, history should be a +straight-forward progression of versions. Once you have more versions, +it will look something like: + +.. digraph:: pristine_dag + + rankdir=LR + node [shape=square] + subgraph cluster_pristine { + a -> b -> c + a [label="1.0"] + b [label="1.1"] + c [label="2.0"] + label = "pristine" + color = white + labeljust = r + } + +Scriptsify +---------- + +In a perfect world, the pristine version would be equivalent to the scriptsified +version that would actually get deployed. However, we have historically needed +to apply patches and add extra configuration files to get applications to +work correctly. Due to the way Git's merge algorithm works, the closer we are +able to reconstruct a version of the application that was actually used, the +better off we will be when we try to subsequently upgrade those applications. + +To give you an idea of what the Git history graph will look like when we +are done, here is the graph from before, but augmented with the scripts versions: + +.. digraph:: master_dag + + rankdir=LR + node [shape=square] + subgraph cluster_pristine { + a -> b -> c + a [label="1.0"] + b [label="1.1"] + c [label="2.0"] + label = "pristine" + color = white + labeljust = r + } + subgraph cluster_master { + as -> bs -> cs + as [label="1.0-scripts"] + bs [label="1.1-scripts"] + cs [label="2.0-scripts"] + label = "master" + color = white + labeljust = r + } + a -> as + b -> bs + c -> cs + a [] + +.. highlight:: sh + +First things first: verify that we are on the master branch:: + + git checkout master + +Check for pre-existing patches in the old application directory, +:file:`/mit/scripts/deploy/wordpress-2.0.2` in the case of Wordpress, +and apply them:: + + patch -n0 < /mit/scripts/deploy/wordpress-2.0.2/wordpress.patch + +Then, run the following command to setup a :file:`.scripts` directory:: + + wizard prepare-new + +This directory holds Wizard related files, and is also used by +:command:`parallel-find.pl` to determine if a directory is an autoinstall. + +Finally, if you are running a PHP application, you'll need to setup +a :file:`php.ini` and symlinks to it in all subdirectories:: + + cp /mit/scripts/deploy/php.ini/wordpress php.ini + athrun scripts fix-php-ini + +.. note:: + + As of November 2009, all PHP applications load the same :file:`php.ini` file. + +Now commit, but don't get too attached to your commit; we're going +to be heavily modifying it soon:: + + git commit -asm "Wordpress 2.0.2-scripts" + +Installation +------------ + +We now need to make it possible for a user to install the application. +Most web applications have a number of web scripts for generating a +configuration file, so creating the install script involves: + + 1. Determining what input values you will need from the user, such + as a title for the new application or database credentials; more + on this shortly. + + 2. Determining what POST values need to be sent to what URLs. + Since you're converting a repository, this job is even simpler: you just + need to port the Perl script that was originally used into Python. + +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) + +Some tips and tricks for writing :meth:`wizard.app.Application.install`: + + * Some configuration file generators will get unhappy if the + target directory is not chmod'ed to be writable; dropping + in a ``os.chmod(dir, 0777)`` and then undoing the chmod + when you're done is a decent workaround. + + * :func:`wizard.install.fetch` is the standard workhorse for making + requests to applications. It accepts three parameters; the first + is ``options`` (which was the third argument to ``install`` itself), + the second is the page to query, relative to the installation's + web root, and ``post`` is a dictionary of keys to values to POST. + + * You should log any web page output using :func:`logging.debug`. + + * If you need to manually manipulate the database afterwards, you + can use :func:`wizard.sql.mysql_connect` (passing it ``options``) + to get a `SQLAlchemy metadata object + `_, which can + consequently be queried. For convenience, we've bound metadata + to the connection, you can perform implicit execution. + +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:: + + #!/bin/bash -e + + DEFAULT_HEAD=1 + TESTNAME="install_wordpress" + source ./setup + + wizard install "wordpress-$VERSION-scripts" "$TESTDIR" --non-interactive -- --title="My Blog" + +``DEFAULT_HEAD=1`` indicates that this script can perform a reasonable +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. (to be continued) diff --git a/wizard/app/__init__.py b/wizard/app/__init__.py index 4ec8ea6..929cacf 100644 --- a/wizard/app/__init__.py +++ b/wizard/app/__init__.py @@ -76,6 +76,9 @@ class Application(object): #: a conflict marker string and a result list. See :mod:`wizard.resolve` #: for more information. resolutions = {} + #: Instance of :class:`wizard.install.ArgSchema` that defines the arguments + #: this application requires. + install_schema = None def __init__(self, name): self.name = name self.versions = {}