Free to good home: rails-app-installer

I really should have done this nine months ago, but I just don’t have time to devote to my rails-app-installer project, and I’d love it if someone would volunteer to take it over.

This is the installer used in the Typo GEM; it’s designed to make it easy to turn any Rails app into an easily-installed GEM.

The code lives in Google Code; feel free to take a look around.

If you’re interested, then please either send me mail or let me know in person at OSCON this week.

Posted by Scott Laird Tue, 24 Jul 2007 14:20:00 GMT


Typo 4.0.2

I just released Typo 4.0.2. This is mostly a security upgrade; it’s designed to work with Rails 1.1.6, but it also includes workarounds for all of the known Rails 1.1.x security bugs, thanks to Piers Cawley.

In addition, we’ve fixed several bugs in the installer. MySQL users should be able to upgrade from 4.0.0 or 4.0.1 without problems now, fixing a problem with the 4.0.1 upgrader.

Upgrade directions:

Repeat however you installed Typo in the first place. If you downloaded the .tgz or .zip files, then you’ll need to download them again and install them over the top of your existing install. Then run rake migrate and restart your Typo processes.

If you’re using the .gem installer, just run gem install typo and then typo install /some/path to upgrade.

Posted by Scott Laird Thu, 10 Aug 2006 21:11:33 GMT


Rails 1.1.5 is still broken, here's a workaround

Apparently Rails 1.1.5 is still broken. It fixed one attack but left a couple other holes open. Piers has a workaround that should work for any Rails app.

Now would be a great time to fix this, because the exploit is fairly obvious right now.

Posted by Scott Laird Thu, 10 Aug 2006 16:28:07 GMT


Typo 4.0.1

I just released Typo 4.0.1. By and large, this is a bug-fix release. Please make sure that you use Typo 4.0.1 with Rails 1.1.5, as earlier versions (1.1.4 especially) have substantial security problems.

A number of changes were made to the installer for this release:

  • It has been spun off into its own .gem and lives in its own source repository, so other projects can use it as well.
  • It now supports Postgres as well as SQLite3. I’ll write about this soon.
  • It performs database-agnostic backups to a .yml file.
  • A number of bugs have been squashed.

If you installed Typo 4.0.0 via the new installer, then upgrading is easy–just gem install typo and then typo install /some/path to upgrade. If you’re using the tar or zip files from Rubyforge, then unpack them over the top of your existing install, run ‘gem install rails’ to make sure that you have Rails 1.1.5, run ‘rake migrate’, and then restart your FastCGI processes.

If you’re installing for the first time, then you’ll probably find the .gem installer to be easier. If you can install things as root (or your hosting provider has already installed the Typo .gem), then do this:

  $ sudo gem install typo
  $ typo install /some/path

If you don’t have the ability to run gem install as root, then do this:

  $ export GEM_PATH=~/gems
  $ gem install -i ~/gems typo
  $ ~/gems/bin/typo install /some/path

As usual, let me know if you hit problems.

Posted by Scott Laird Thu, 10 Aug 2006 07:22:03 GMT


Rails 1.1.5

The Rails team just released Rails 1.1.5, a “mandatory security” upgrade. So, if you’re running Rails, now would be a great time to upgrade.

I’m going to release Typo 4.0.1 tonight, including Rails 1.1.5 and a bunch of bug fixes.

Posted by Scott Laird Wed, 09 Aug 2006 21:13:28 GMT


How to install gems when you're not root

A number of people have had a hard time installing Typo from the .gem on hosting providers’ systems where they don’t have the ability to install things as root. So, I sat down with Jim Weirich at OSCON to talk over the best way to handle non-root installs. Apparently RubyGems has support for this, plus or minus a few bugs. Try this:

  $ export GEM_PATH=~/gems
  $ gem install -i ~/gems typo
  $ ~/gems/bin/typo install /some/path

Rubygems 0.9.0 will end up re-installing .gems that are already installed in the system gem directory, but that’s not fatal. It’s just a bit slower then it should be.

Hopefully the next rubygems release will fix this and add a “you aren’t running as root, use -i” warning.

Posted by Scott Laird Fri, 28 Jul 2006 19:50:40 GMT


Rail Application Installer

I’ve mostly finished extracting Typo’s installer into its own Rails project and .gem. The installer makes it trivial to build an installable .gem for any Rails project, so the install process looks like this:

$ gem install my-project
$ my-project install /some/path

The installer source lives in Google Code. That includes a mailing list and bug tracker. I’ll upload my .gem to RubyForge later today, along with some documentation. For now, the rdoc is available.

Here’s what you’ll need to do to add the installer to your existing Rails app:

  1. Create a .gem that depends on rails-app-installer, rails, and all other .gems that you need to have installed.
  2. Add an executable entry to your gemspec. If your app is called my-app, then add executable = ['my-app'].
  3. Finally, create bin/my-app, using one of the examples in the rails-app-installer SVN tree as an example.

Here’s a short example bin/my-app:

  #!/usr/bin/env ruby

  require 'rubygems'
  require 'rails-installer'

  class AppInstaller < RailsInstaller
    application_name 'my_app'
    support_location 'my website'
    rails_version '1.1.4'
  end

  # Installer program
  directory = ARGV[1]

  app = AppInstaller.new(directory)
  app.message_proc = Proc.new do |msg|
    STDERR.puts " #{msg}"
  end
  app.execute_command(*ARGV)

That’s all that’s needed–as long as the installer gem is installed, this will give you a full installer that supports installs, upgrades, db backups and restores, and all of the other things that the Typo installer currently provides. Adding application-specific installer subcommands is easy. Here’s the sweep_cache implementation from Typo’s installer:

  class SweepCache < RailsInstaller::Command
    help "Sweep Typo's cache"

    def self.command(installer, *args)
      installer.sweep_cache
    end
  end

That’s all that’s needed to implement the typo sweep_cache /some/path installer command.

Update: The gem is out. gem install rails-app-installer.

Posted by Scott Laird Fri, 28 Jul 2006 17:53:08 GMT


Rails Schema Generator 0.1.0

I just uploaded the first version of my schema generator to rubyforge. This is a Rails generator that knows how to take a collection of migration scripts and use them to build up a valid SQL schema file.

You should be able to install it via gem install schema_generator, and run it on any Rails project by running ./script/generate schema from the root of the Rails project. The current release (0.1.0) supports MySQL, PostgreSQL, and SQLite. It will auto-generate a schema for each DB in db/schema.DBTYPE.sql every time it runs, prompting you before overwriting existing files.

For this to work, your Rails migrations must describe your complete database schema. Many projects, like Typo, are older then Rails’s migration support, so their migrations don’t start with a clean slate; instead they describe how to migrate from a specific old version of the DB schema to the current version. In this case, either create a 0_initial_schema migration or to modify the existing migration #1 to create all of the original tables. I just committed an example to Typo’s subversion tree, feel free to use it as an example.

Here’s an example of the a schema generated by the generator. This is for Typo on PostgreSQL, as of migration #14. I had to create a db/migrate/0_initial_schema.rb file, but all of the other migrations were completely untouched.

The schemas for MySQL and SQLite are similar, but use the correct types (like int(11)) and syntax for each DB.

-- This file is autogenerated by the Rail schema generator, using
-- the schema defined in db/migration/*.rb
--
-- Do not edit this file.  Instead, add a new migration using
-- ./script/generate migration <name>, and then run
-- ./script/generate schema

-- tables 

CREATE TABLE articles (
  id serial primary key,
  title character varying(255),
  author character varying(255),
  body text,
  body_html text,
  extended text,
  excerpt text,
  keywords character varying(255),
  allow_comments integer,
  allow_pings integer,
  published integer DEFAULT '1',
  created_at timestamp,
  updated_at timestamp,
  extended_html text,
  guid character varying(255),
  permalink character varying(255),
  user_id integer,
  text_filter_id integer
);

CREATE TABLE articles_categories (
  article_id integer,
  category_id integer,
  is_primary integer
);

CREATE TABLE articles_tags (
  article_id integer,
  tag_id integer
);

CREATE TABLE blacklist_patterns (
  id serial primary key,
  type character varying(255),
  pattern character varying(255)
);

CREATE TABLE categories (
  id serial primary key,
  name character varying(255),
  position integer,
  permalink character varying(255)
);

CREATE TABLE comments (
  id serial primary key,
  article_id integer,
  title character varying(255),
  author character varying(255),
  email character varying(255),
  url character varying(255),
  ip character varying(255),
  body text,
  body_html text,
  created_at timestamp,
  updated_at timestamp
);

CREATE TABLE page_caches (
  id serial primary key,
  name character varying(255)
);

CREATE TABLE pages (
  id serial primary key,
  name character varying(255),
  user_id integer,
  body text,
  body_html text,
  created_at timestamp,
  updated_at timestamp,
  title character varying(255),
  text_filter_id integer
);

CREATE TABLE pings (
  id serial primary key,
  article_id integer,
  url character varying(255),
  created_at timestamp
);

CREATE TABLE resources (
  id serial primary key,
  size integer,
  filename character varying(255),
  mime character varying(255),
  created_at timestamp,
  updated_at timestamp,
  article_id integer
);

CREATE TABLE sessions (
  id serial primary key,
  sessid character varying(255),
  data text,
  created_at timestamp,
  updated_at timestamp
);

CREATE TABLE settings (
  id serial primary key,
  name character varying(255),
  value character varying(255),
  position integer
);

CREATE TABLE sidebars (
  id serial primary key,
  controller character varying(255),
  active_position integer,
  active_config text,
  staged_position integer,
  staged_config text
);

CREATE TABLE tags (
  id serial primary key,
  name character varying(255),
  created_at timestamp,
  updated_at timestamp
);

CREATE TABLE text_filters (
  id serial primary key,
  name character varying(255),
  description character varying(255),
  markup character varying(255),
  filters text,
  params text
);

CREATE TABLE trackbacks (
  id serial primary key,
  article_id integer,
  blog_name character varying(255),
  title character varying(255),
  excerpt character varying(255),
  url character varying(255),
  ip character varying(255),
  created_at timestamp,
  updated_at timestamp
);

CREATE TABLE users (
  id serial primary key,
  login character varying(255),
  password character varying(255),
  email text,
  name text
);


-- indexes 

CREATE  INDEX articles_permalink_index ON articles (permalink);
CREATE  INDEX blacklist_patterns_pattern_index ON blacklist_patterns (pattern);
CREATE  INDEX categories_permalink_index ON categories (permalink);
CREATE  INDEX comments_article_id_index ON comments (article_id);
CREATE  INDEX page_caches_name_index ON page_caches (name);
CREATE  INDEX pings_article_id_index ON pings (article_id);
CREATE  INDEX trackbacks_article_id_index ON trackbacks (article_id);

-- data 

INSERT INTO sidebars ("staged_position", "active_config", "active_position", "controller", "staged_config") VALUES(NULL, NULL, 0, 'category', NULL);
INSERT INTO sidebars ("staged_position", "active_config", "active_position", "controller", "staged_config") VALUES(NULL, NULL, 1, 'static', NULL);
INSERT INTO sidebars ("staged_position", "active_config", "active_position", "controller", "staged_config") VALUES(NULL, NULL, 2, 'xml', NULL);
INSERT INTO text_filters ("name", "filters", "description", "params", "markup") VALUES('none', '--- []', 'None', '--- {}', 'none');
INSERT INTO text_filters ("name", "filters", "description", "params", "markup") VALUES('markdown', '--- []', 'Markdown', '--- {}', 'markdown');
INSERT INTO text_filters ("name", "filters", "description", "params", "markup") VALUES('smartypants', '--- 
- :smartypants', 'SmartyPants', '--- {}', 'none');
INSERT INTO text_filters ("name", "filters", "description", "params", "markup") VALUES('markdown smartypants', '--- 
- :smartypants', 'Markdown with SmartyPants', '--- {}', 'markdown');
INSERT INTO text_filters ("name", "filters", "description", "params", "markup") VALUES('textile', '--- []', 'Textile', '--- {}', 'textile');

-- schema version meta-info 

CREATE TABLE schema_info (
  version integer
);

insert into schema_info (version) values (14);

Posted by Scott Laird Sat, 03 Sep 2005 08:09:00 GMT


Rails schema generation is nearly complete

My Rails Schema Generator is nearly complete. Here’s a sample run:

$ ./script/generate schema
Found 6 migration classes
Starting migration for AddSidebars
Starting migration for AddCacheTable
Starting migration for AddPages
Starting migration for AddPageTitle
Starting migration for AddTags
Starting migration for AddTextfilters
Adding TextFilters table
Migrations complete.
 Tables found:   6
 Indexes found: 1
 Records found:   8
      exists  db
overwrite db/schema.postgresql.sql? [Ynaq] y
       force  db/schema.postgresql.sql
overwrite db/schema.mysql.sql? [Ynaq] y
       force  db/schema.mysql.sql
overwrite db/schema.sqlite.sql? [Ynaq] y
       force  db/schema.sqlite.sql

The migration classes that I’m using are copied straight from Typo without modification. I’ve left out all of the migrations that add features to “legacy” tables–tables like articles–since there isn’t a table definition that I can use. That’s my next project–adding a 0_initial_schema migration for Typo. Once that’s complete, I have a bit of code cleanup and then I’ll release my schema generator code to the world. Hopefully that’ll be later today.

Posted by Scott Laird Fri, 02 Sep 2005 22:56:00 GMT


Changes in Direction

Yesterday was an interesting day–my now-former employer is restructuring “to support changes in direction and a new funding strategy,” so I’m now looking at new modes of employment, as are several former co-workers.

I’m viewing this as more of an opportunity to move on to new things, rather then a setback. I’ve spent quite a bit of time over the past few months thinking about what I wanted to do next, even though I didn’t expect this job to end quite so suddenly.

Here’s what I’ve decided:

  1. I don’t want to work on long, slow, multi-year projects. The world doesn’t work that way anymore. Agility is the future, and I’m not going to enjoy working for any company that takes years to bring a product to market.
  2. I want to work on things that I enjoy and challenge me, like Ruby and Rails.
  3. I want to spend less time commuting.
  4. I’d like the freedom to follow interesting trends and opportunities as they arise, for my own profit and the profit of those I work for.

With these goals in mind, I’ve decided to start looking for Rails consulting/contract work, although I’m also willing to consider full-time employment in the right environment. Please forgive a bit of shameless self-promotion:

My background is a combination of Unix system administration and programming; I’m very good at getting things to work and keeping them working. I’ve been programming professionally since 1988, I have 3 years of Ruby experience, over 6 months of Rails experience, and 13 years of Linux experience. I’m a major contributor to Typo, a Rails-based blog engine; I can easily provide code samples for those who are interested. I’ve written extensively about Typo, Rails, and Ruby here on my blog, feel free to look around. I was once the senior system administrator in charge of over 700 production Linux, BSD, and Solaris systems in a 24x7 environment; I can handle any level of system administration task that may be required.

Most importantly, I’m used to working with small groups of people to design effective, scalable, and affordable solutions to their problems.

Over the next few days I’ll post more details on this site, including a resume and some details on previous experiences. For now, if you have questions, please feel free to send me email, and I’ll get back to you as soon as possible.

Posted by Scott Laird Fri, 02 Sep 2005 02:26:00 GMT