.. code-block:: python
- def checkConfig(self, deployment):
- return os.path.isfile("wp-config.php")
+ class Application(app.Application):
+ # ...
+ 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
.. 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])
+ class Application(app.Application):
+ # ...
+ 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']
+ class Application(app.Application):
+ # ...
+ 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
+ class Application(app.Application):
+ # ...
+ parametrized_files = ['wp-config.php'] + php.parametrized_files
+
+And finally, we have :attr:`~wizard.app.Application.extractors` and
+:attr:`~wizard.app.Application.substitutions`. At the bare metal, these
+are simply dictionaries of variable names to functions: when you call the
+function, it performs either an extraction or a substitution. However, we can
+use higher-level constructs to generate these functions for us.
+
+The magic sauce is a data structure we'll refer to as ``seed``. Its form is
+a dictionary of variable names to a tuple ``(filename, regular expression)``.
+If we manually coded one out, it might look like:
+
+.. code-block:: python
+
+ seed = {
+ 'WIZARD_DBSERVER': ('wp-config.php', re.compile(r'''^(define\('DB_HOST', )(.*)(\))''', re.M)),
+ 'WIZARD_DBNAME': ('wp-config.php', re.compile(r'''^(define\('DB_NAME', )(.*)(\)), re.M)),
+ }
+
+There's a lot of duplication, though. For one thing, the regular expressions are almost
+identical, safe for a single substitution within the string. We have a function
+:meth:`wizard.app.php.re_define` that does this for us:
+
+.. code-block:: python
+
+ seed = {
+ 'WIZARD_DBSERVER': ('wp-config.php', php.re_define('DB_HOST')),
+ 'WIZARD_DBNAME': ('wp-config.php', php.re_define('DB_NAME')),
+ }
+
+.. note::
+
+ If you find yourself needing to define a custom regular expression generation function,
+ be sure to use :func:`wizard.app.expand_re`, which will escape an incoming variable
+ to be safe for inclusion in a regular expression, and also let you pass a list,
+ and have correct behavior. Check out :mod:`wizard.app.php` for some examples.
+
+We can shorten this even further: in most cases, all of the configuration values live in
+one file, so let's make ourselves a function that generates the whole tuple:
+
+.. code-block:: python
+
+ def make_filename_regex_define(var):
+ return 'wp-config.php', php.re_define(var)
+
+Then we can use :func:`util.dictmap` to apply this:
+
+.. code-block:: python
+
+ seed = util.dictmap(make_filename_regex_define, {
+ 'WIZARD_DBSERVER': 'DB_HOST',
+ 'WIZARD_DBNAME': 'DB_NAME',
+ 'WIZARD_DBUSER': 'DB_USER',
+ 'WIZARD_DBPASSWORD': 'DB_PASSWORD',
+ })
+
+Short and sweet. From there, setting up :attr:`~wizard.app.Application.extractors` and
+:attr:`~wizard.app.Application.substitutions` is easy:
+
+.. code-block:: python
+
+ class Application(app.Application):
+ # ...
+ extractors = app.make_extractors(seed)
+ extractors.update(php.extractors)
+ substitutions = app.make_substitutions(seed)
+ substitutions.update(php.substitutions)
+
+Note how we combine our own dictionaries with the dictionaries of :mod:`wizard.app.php`, much like
+we did for :attr:`~wizard.app.Application.parametrized_files`.
+
+With all of these pieces in place, run the following command::
+
+ wizard prepare-config
+
+If everything is working, when you open up the configuration files, any user-specific
+variables should have been replaced by ``WIZARD_FOOBAR`` variables. If not, check
+your regular expressions, and then try running the command again.
+
+When you are satisfied with your changes, add your files, amend your previous
+commit with these changes and force them back into the public repository::
+
+ git status
+ git add wp-config.php
+ git commit --amend -a
+ git push --force
+
+Ending ceremonies
+-----------------
+
+Congratulations! You have just implemented the installation code for a new install.
+If you have other copies of the application checked out, you can pull the forced
+change by doing::
+
+ git reset --hard HEAD~
+ git pull
+One last thing to do: after you are sure that your commit is correct, tag the new
+commit as ``appname-x.y.z-scripts``, or in this specific case::
+ git tag wordpress-2.0.4-scripts
+ git push --tags