Upgrading to Mephisto 0.8.1

January 14th, 2009

Last month Mephisto 0.8.1: Drax was relaunched. Seeing activity on Mephisto was great news in itself. The update includes support for Rails 2.2.2 and several significant security fixes. The release is considered experimental but important because of the security fixes. That's a bit of a mixed message but I have no financial stake in my blog so decided to do an update.

This post describes my update process. It provides some general information about the changes and provides an example of using interactive git rebasing but in most cases it won't be a cookie cutter approach that you can follow for your own Mephisto implementation. In gitting Started with Mephisto and other posts I've described how I set-up Mephisto 0.8. Unless you've followed along and are maintaining Mephisto in the same way, or at least maintain your Mephisto blog in a git repository with customizations in your own branch, then your update procedure will probably be significantly different.

I should point out that I've been using the technoweenie version of Mephisto from github and not the emk version where all of the latest experimental work is going on. When I pulled from the master the latest commit in technoweenie branch was very close to the emk v0.8.1 (v0.8-stable) tag that marked the version that's available for download from the Mephisto site. The only additional commits in the official release were a safe_erb test update and emk-safe-erb was updated from 0.1.1 to 0.1.2. The main point is that when I talk about pulling the latest master, it's really a fairly stable version. At some point I may migrate over to emk but so far I haven't had a compelling reason to do so.

The Original Plan

In gitting Started with Mephisto I described my upgrade strategy for future releases using rebasing:

[mac]$ git checkout master
[mac]$ git pull
[mac]$ git checkout robseaman
[mac]$ git rebase master

The Updated Plan

When it came time to move to 0.8.1 I stuck with that basic concept but added a few details like a backup step and an interactive rebase instead of an automatic one. There were several reasons for going with an interactive rebase, the biggest ones were that I'd installed Rails 2.0.2 in vendor and used Cached Externals. Allowing the commits associated with those changes when I knew Mephisto had added support for Rails 2.2.2 and probably also changed other externals would result in a bunch of messy conflicts that I'd need to resolve, assuming it worked at all. Interactive rebasing would provide the control I needed to make the rebase reasonably clean. The first steps were to do a backup and pull down the latest Mephisto master branch:

[mac]$ cap data:load_from_prod
[mac]$ cd ..
[mac]$ cp -r mephisto mephisto_backup
[mac]$ cd mephisto
[mac]$ git checkout master
[mac]$ git pull

$ cap data:load_from_prod (see Production Data to Development for details) and the copy created a backup of the production database and 0.8 version. After the git-pull I ended up with revision e229865d6e63a6b6c0e6cb7aac21992ca303f94a of Mephisto.

With the latest master in hand I looked for changes that would impact my rebase process. More specifically I was looking for changes to any of the externals that I'd been caching (see Cached Externals). The first thing that stood out is that my pull of Mephisto included TZInfo-0.3.12 in the vendor/gems directory. TZInfo can't be vendorized so it shouldn't be there. In fact the first development commit (emk repository) made after the 0.8.1 release was to remove it. See Should TZInfo be included in vendor/gems? for details. Since the vendorized copy won't be used make sure you follow 0.8.1 download page instructions: "Before installing: Run sudo gem install tzinfo". Alternately you can make sure you have all the gems including TZInfo installed on your target by running:

[mac]$ rake gems:install

On with the rest of the inspection, I already knew I'd need to upgrade to Rails 2.2.2 and of course it wasn't embedded so the next step was to inspect the RSpec directories. The old 2962 versions in 0.8 were from subversion repositories. I knew that a lot of work went into updating the tests for Mephisto so I wasn't surprised to find the RSpec directories contained updated copies of git repositories. A search for "rspec" in gitk showed a checkin comment indicating that the latest github versions available on 12-4-2008 were used. Going over to github's rspec commits the last commit before 12-4-2008 was f85a53bb54b13e6461c8ffbded4933b90e40a86c and the commit for rspec-rails was f96eb3fd4d95eb400e87b4f1cf8e6a279f1dbcbd.

Interactive Rebasing

OK, now I had the basic information I knew I'd need. With that background I moved on to checkout my custom branch and start the interactive rebase:

[mac]$ git checkout robseaman
[mac]$ git rebase -i master

Interactive rebasing opens a file called git-rebase-todo in your editor. git-rebase-todo contains a list of the branch's commits with an action to be applied to each one. The default is to pick (apply) each one and apply them in order but they can be squashed (merged), edited after they are applied, deleted or reordered. Here was a pseudo edit copy of my list showing the changes I decided to make:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
e f2b123a Changed to track changes for my blog.
DELETE> pick f25ef13 Froze to Rails 2.0.2.
DELETE> pick 286a82d Updated to Rails 2.0.2 boot.rb.
DELETE> pick c8efd30 Put tzinfo 0.3.12 in vendor dir.
pick dcddd47 Changed secret from distributed version.
pick 0c1579c Disabled multi-site support.
pick f78a7d3 Ran db:bootstrap
pick 7c4f203 Initial versions from capify.
pick d1d5efc First customized version of deploy.rb
pick 9a4a736 Added Railscasts CodeRay style.
pick 4cead81 Updated styles for coderay.
DELETE> pick b6e7478 Added doc directory.
pick b1ac0ef Restyled sidebar and meta fields.
e 5c0bdb4 Added Cached Externals plugin.
DELETE> pick f7308b9 Created externals YAML file.
DELETE> pick 4ff2557 Cached Externals: rails, tzinfo & rspec/rspec_rails
pick 4105041 Change the application user.
pick 5c29462 Added section article count, change tags to use linebreak as separator.
pick 40507f7 Added more coderay standard defs to help code match to linenums.
pick 0289fc4 Added standard coderay.css (from coderay_stylesheet) for reference.
pick 6ff1ba4 Increased top and bottom padding to give a little breathing room.
pick d978f48 Added git://github.com/caritos/action_mailer_tls.git for TLS mail support.
pick a874664 Added gmail blog account settings.
DELETE> pick 4d153be Added action_mailer_tls to the externals list.
pick 66bc24c Commented out display of links to other pages in the same section.
pick 0bfb9c8 Removed Search sidebar title, Added min-nav icon section.
pick df51dd7 Added email subscriptions.
pick 11905d1 Changed mini-nav icon to include text and increased site font size.
pick b1c246b Changed Contact to 'Contact Me'.
pick 58d48cd Changed Contact Me to just Contact.

# Rebase e229865..58d48cd onto e229865
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

The line 1 commit contained changes to .gitinore and line 12 was a .gitinore for a doc directory where I save HTML edits of articles. I deleted line 12 and changed line 1 to an edit point so that I could recall the commit and do all .gitinore changes at once. I deleted lines 2-4 because I wanted to add Rails 2.2.2 and take care of TZInfo as part of the Cached Externals setup, something that I'd redo after the plugin was added after line 14. I deleted line 24 because I decided not to continue to include the action_mailer_tls plugin in my Cached Externals setup. I was on the fence about adding it in the first place; the plugin is so small that it didn't provide a performance benefit. My reason for adding it was simply documentation to keep track of its revision information but I have that recorded elsewhere. Leaving it out meant one less consideration the next time I updated Mephisto.

After saving the file there was an immediate conflict on the first commit:

warning: too many files, skipping inexact rename detection
Auto-merged .gitignore
CONFLICT (content): Merge conflict in .gitignore
Automatic cherry-pick failed.  After resolving the conflicts,
mark the corrected paths with 'git add ', and
run 'git rebase --continue'
Could not apply f2b123a... Changed to track changes for my blog.

A new .gitignore

Here's what .gitinore contained:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.DS_Store
<<<<<<< HEAD:.gitignore
.rake_tasks
Capfile
config/database.yml
config/deploy.rb
config/initializers/session_store.rb
db/*.sqlite3
log/*.log
public/assets
public/cache
public/plugin_assets
tmp
themes
*~
=======
config/database.yml
log
tmp
public/assets
>>>>>>> f2b123a... Changed to track changes for my blog.:.gitignore

I covered setting up the .gitinore in gitting Started with Mephisto but there were some new considerations with Mephisto's 0.8.1 .gitinore. Here were the additional things I considered when deciding how to resolve the conflict:

  • config/initializers/session_store.rb is a file that Mephisto now generates to avoid the weakness with using a common session secret. Something I had worked around in my original post by generating my own key. The file is generated as part of the bootstrap process or it can be created independently with a new db:bootstrap:session or config/initializers/session_store.rb rake task. It's obvious the file doesn't belong in Mephisto's project repository on github but I decided to leave it in my private git repository of Mephisto to make deployment easy.
  • db/*.sqlite3 is a new ignore. I'm not using SQLite but I decided I'd ignore these files in case they get generated automatically as part of running the test suite.
  • public/assets was something that I had already added. public/cache and public/plugin_assets are automatically generated by Mephisto and not part of the code base so I decided I'd also make them part of my .gitignore.
  • *~ is for Emacs backup files. I'm not using Emacs so I didn't bother with adding it.
  • log/*.log is a more specific ignore for log files. I don't see much significance but went with the new method to keep my implementation in sync if something important happens to get added to the log directory so I decided to accept this change.
  • The doc directory is something I'd originally added to .gitinore as a separate commit but deleted the line in interactive mode so I could add it after this first .gitignore commit. Since there was a conflict I decided I'd add it as part of this conflict resolution.

So that lead to this version of .gitignore:

1
2
3
4
5
6
7
8
9
.DS_Store
db/*.sqlite3
log/*.log
public/assets
public/cache
public/plugin_assets
tmp
config/database.yml
doc

Resolving Conflicts

Adding the resolution and continuing is the standard thing to do after resolving a conflict:

[mac]$ git add .gitignore
[mac]$ git rebase --continue
warning: too many files, skipping inexact rename detection
Auto-merged config/environment.rb
CONFLICT (content): Merge conflict in config/environment.rb
Automatic cherry-pick failed.  After resolving the conflicts,
mark the corrected paths with 'git add ', and
run 'git rebase --continue'
Could not apply dcddd47... Changed secret from distributed version.

I wasn't surprised by this config/environment.rb problem. I knew I'd updated the file to create my own session key and had just discovered there was a fix for this in Mephisto with the addition of config/initializers/session_store.rb to .gitignore. So now I needed to delete the following lines (my original change):

57
58
59
60
61
62
63
64
<<<<<<< HEAD:config/environment.rb
=======
  # Use the database for sessions instead of the file system
  # (create the session table with 'rake create_sessions_table')
  # config.action_controller.session_store = :active_record_store
  config.action_controller.session = { :session_key => "_mephisto_session", ....

>>>  >>> dcddd47... Changed secret from distributed version.:config/environment.rb

And move on:

[mac]$ git add config/environment.rb
[mac]$ git rebase --continue
warning: too many files, skipping inexact rename detection
Auto-merged config/initializers/custom.rb
CONFLICT (content): Merge conflict in config/initializers/custom.rb
Automatic cherry-pick failed.  After resolving the conflicts,
mark the corrected paths with 'git add ', and
run 'git rebase --continue'
Could not apply 0c1579c... Disabled multi-site support.

This custom.rb conflict occurred because I had disabled multisite support near another change that went into 0.8.1:

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<<<<<<< HEAD:config/initializers/custom.rb
  # TODO - We need to wrap these options in Dispatcher.to_prepare, because
  # the underlying Site, etc., objects will be unloaded on each request in
  # development mode, and the preferences will be reset.  This is a flaw
  # in how we handle configuration, and to_prepare is just a workaround.
  Dispatcher.to_prepare do
    # Turn this on to get detailed cache sweeper logging in production mode
    # Site.cache_sweeper_tracing = true
=======
# Enable if you want to host multiple sites on this app
# Site.multi_sites_enabled = true
>>>>>>> Disabled multi-site support.:config/initializers/custom.rb

    # Enable if you want to host multiple sites on this app
    Site.multi_sites_enabled = true

Last spring Mephisto was changed to enable multisite support by default but most people will probably encounter it for the first time in 0.8.1. I discussed why I disabled it in gitting Started with Mephisto. Hopefully it's working fine now (if it wasn't before) but I still don't need multisite support and decided to keep it disabled so I deleted lines 8,16-19 and commented out line 22:

22
# Site.multi_sites_enabled = true

I do have a side note here. If you decide to leave Site.multi_sites_enabled set to true and you're using Phusion Passenger then there is one consideration that I've become aware of: Enabling multisite support causes your cache files to be placed under a cache directory (i.e. public/cache/site.com) instead of in public root. If you want Passenger to find the cached files may may need mod_rewrite modifications. Check out Paul Gross's Mephisto with Phusion Passenger post for details. Oh well, that's not an issue for me so on to the next stop:

[mac]$ git add config/initializers/custom.rb
[mac]$ git rebase --continue
Could not apply 0c1579c... Disabled multi-site support.
Robs-Laptop-2:mephisto Rob$ git add config/initializers/custom.rb
Robs-Laptop-2:mephisto Rob$ git rebase --continue
Created commit 47398d9: Disabled multi-site support.
 1 files changed, 1 insertions(+), 1 deletions(-)
Stopped at 5c0bdb4... Added Cached Externals plugin.
You can amend the commit now, with

	git commit --amend

Once you are satisfied with your changes, run

	git rebase --continue

Updating Cached Externals

Finally, I hit my first planned stop after the plugin was added. At this point I needed to complete the Cached Externals setup, which was pretty much a subset of what I had done in my Cached Externals post.

Although TZInfo was installed in vendor/gems in my copy of Mephisto, as I mentioned above it'll be gone in the next stable release. Vendorized versions of TZInfo won't be loaded, at least for now, because Rails (2.1.2+) loads its own TZInfo version that is unfortunately just a subset without support for TimezoneProxy which is required by Mephisto when you access Admin/Settings. Since it can't be vendorized I verified that 3.12 was installed on my production server and no longer plan to cache it. I was tempted to remove the gem from my Mephisto implementation but decided to live with it being there for now and wait for the next stable Mephisto release.

I did want to cache the new RSpec versions so the current vendor copies needed to be removed:

[mac]$ rm -rf vendor/plugins/rspec
[mac]$ rm -rf vendor/plugins/rspec_on_rails

There was no need to freeze Rails 2.2.2, delete it and then include it as a Cached External. Just making it part of config/externals.yml would effectively freeze it into vendor. So, using information from the 2.2.2 tag on github and what I'd found after the pull, here was my new config/externals.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
vendor/rails:  # v2.2.2
  :type: git
  # DH old git checkout (1.4.4.4) doesn't support -q
  :scm_verbose: true
  :repository: git://github.com/rails/rails.git
  :revision: ff561370739eb809d1d006ea842cd2b1e43f6950
vendor/plugins/rspec: # 12-4-2008
  :type: git
  # DH old git checkout (1.4.4.4) doesn't support -q
  :scm_verbose: true
  :repository: git://github.com/dchelimsky/rspec.git
  :revision: f85a53bb54b13e6461c8ffbded4933b90e40a86c
vendor/plugins/rspec_on_rails: # 12-4-2008
  :type: git
  # DH old git checkout (1.4.4.4) doesn't support -q
  :scm_verbose: true
  :repository: git://github.com/dchelimsky/rspec-rails.git
  :revision: f96eb3fd4d95eb400e87b4f1cf8e6a279f1dbcbd

With that file in place it was time to use the configuration to load up the cache and create the symbolic links:

[mac]$ cap local externals:setup

At this point I did a little verification using git-status and then committed my changes:

[mac]$ git add config/externals.yml
[mac]$ git commit config/externals.yml -m "Created externals YAML file."
[mac]$ git add .
[mac]$ git commit -a -m "Cached Externals: rails, rspec and rspec_rails."
[mac]$ git rebase --continue
Successfully rebased and updated refs/heads/robseaman.

Common 0.8.1 Update Stuff

Great, no more conflicts and that completed the rebasing. Just a couple of 0.8.1 update related tasks remained:

[mac]$ rake config/initializers/session_store.rb
[mac]$ git add config/initializers/session_store.rb
[mac]$ git commit config/initializers/session_store.rb -m \
> "Created session key for this Mephisto site."
[mac]$ rake db:migrate
[mac]$ git add db/schema.rb
[mac]$ git commit db/schema.rb -m "Ran migrations for Mephisto update."

To work with the new security scheme config/initializers/session_store.rb needed to be created and since I decided to put it in my git repository it also needed to be committed. 0.8.1 had a new migration so running migrations and checking in the updated schema was also required.

New Theme Locations

I figured I was done but the first time I ran script/server I got a 500 error on my first page load and found this entry in the log:

MissingThemesError (No themes found in 
'/Users/Rob/work/mephisto/themes/development/site-1/simpla'.  
This must be set correctly in the site settings. You may be 
able to fix this by running 'rake db:bootstrap:copy_default_theme'):

After looking around a little I discovered the location of themes for non-production environments was changed to reflect the environment. If you'd rather keep the code that way you could just run in production mode by making sure you have usable production database settings in the database.yml and running script/server -e production from the local environment, or you could keep a separate copy of your production theme in themes/development. I didn't like those solutions, I wanted to run my production theme(s) in the development environment and I didn't want to deal with making sure my development themes were always copied over to production. So, instead of living with the change, I chose to modify the line in Mephisto that sets the THEME_ROOT location in lib/mephisto/theme_root.rb from:

7
    (Rails.env.production? ? "themes" : "themes/#{Rails.env}")

to:

7
    (Rails.env.test? ? "themes/#{Rails.env}" : "themes")

Then I checked in the change and did some verification:

[mac]$ git add lib/mephisto/theme_root.rb
[mac]$ git commit lib/mephisto/theme_root.rb -m \
> "Made themes/ the default themes dir for all except test."
[mac]$ script/server

Deploying to Production

Once I was satisfied that things were working it was time to deploy to production. Deploying Mephisto with Capistrano to DreamHost describes my deployment setup, but I'm doing deployments in a standard way:

[mac]$ cap deploy:migrations

In the end the update wasn't too bad. The upgrade complexities associated with Cached Externals wouldn't have occurred in a normal project, they only existed because I decided to use Cached Externals on someone else's project in my custom branch. Even at that once I figured out what had changed the update went pretty quickly.

Sorry, comments are closed for this article.