Chris@909
|
1 # Generates a migration which migrates all plugins to their latest versions
|
Chris@909
|
2 # within the database.
|
Chris@909
|
3 class PluginMigrationGenerator < Rails::Generator::Base
|
Chris@909
|
4
|
Chris@909
|
5 # 255 characters max for Windows NTFS (http://en.wikipedia.org/wiki/Filename)
|
Chris@909
|
6 # minus 14 for timestamp, minus some extra chars for dot, underscore, file
|
Chris@909
|
7 # extension. So let's have 230.
|
Chris@909
|
8 MAX_FILENAME_LENGTH = 230
|
Chris@909
|
9
|
Chris@909
|
10 def initialize(runtime_args, runtime_options={})
|
Chris@909
|
11 super
|
Chris@909
|
12 @options = {:assigns => {}}
|
Chris@909
|
13 ensure_schema_table_exists
|
Chris@909
|
14 get_plugins_to_migrate(runtime_args)
|
Chris@909
|
15
|
Chris@909
|
16 if @plugins_to_migrate.empty?
|
Chris@909
|
17 puts "All plugins are migrated to their latest versions"
|
Chris@909
|
18 exit(0)
|
Chris@909
|
19 end
|
Chris@909
|
20
|
Chris@909
|
21 @options[:migration_file_name] = build_migration_name
|
Chris@909
|
22 @options[:assigns][:class_name] = build_migration_name.classify
|
Chris@909
|
23 end
|
Chris@909
|
24
|
Chris@909
|
25 def manifest
|
Chris@909
|
26 record do |m|
|
Chris@909
|
27 m.migration_template 'plugin_migration.erb', 'db/migrate', @options
|
Chris@909
|
28 end
|
Chris@909
|
29 end
|
Chris@909
|
30
|
Chris@909
|
31 protected
|
Chris@909
|
32
|
Chris@909
|
33 # Create the schema table if it doesn't already exist.
|
Chris@909
|
34 def ensure_schema_table_exists
|
Chris@909
|
35 ActiveRecord::Base.connection.initialize_schema_migrations_table
|
Chris@909
|
36 end
|
Chris@909
|
37
|
Chris@909
|
38 # Determine all the plugins which have migrations that aren't present
|
Chris@909
|
39 # according to the plugin schema information from the database.
|
Chris@909
|
40 def get_plugins_to_migrate(plugin_names)
|
Chris@909
|
41
|
Chris@909
|
42 # First, grab all the plugins which exist and have migrations
|
Chris@909
|
43 @plugins_to_migrate = if plugin_names.empty?
|
Chris@909
|
44 Engines.plugins
|
Chris@909
|
45 else
|
Chris@909
|
46 plugin_names.map do |name|
|
Chris@909
|
47 Engines.plugins[name] ? Engines.plugins[name] : raise("Cannot find the plugin '#{name}'")
|
Chris@909
|
48 end
|
Chris@909
|
49 end
|
Chris@909
|
50
|
Chris@909
|
51 @plugins_to_migrate.reject! { |p| !p.respond_to?(:latest_migration) || p.latest_migration.nil? }
|
Chris@909
|
52
|
Chris@909
|
53 # Then find the current versions from the database
|
Chris@909
|
54 @current_versions = {}
|
Chris@909
|
55 @plugins_to_migrate.each do |plugin|
|
Chris@909
|
56 @current_versions[plugin.name] = Engines::Plugin::Migrator.current_version(plugin)
|
Chris@909
|
57 end
|
Chris@909
|
58
|
Chris@909
|
59 # Then find the latest versions from their migration directories
|
Chris@909
|
60 @new_versions = {}
|
Chris@909
|
61 @plugins_to_migrate.each do |plugin|
|
Chris@909
|
62 @new_versions[plugin.name] = plugin.latest_migration
|
Chris@909
|
63 end
|
Chris@909
|
64
|
Chris@909
|
65 # Remove any plugins that don't need migration
|
Chris@909
|
66 @plugins_to_migrate.map { |p| p.name }.each do |name|
|
Chris@909
|
67 @plugins_to_migrate.delete(Engines.plugins[name]) if @current_versions[name] == @new_versions[name]
|
Chris@909
|
68 end
|
Chris@909
|
69
|
Chris@909
|
70 @options[:assigns][:plugins] = @plugins_to_migrate
|
Chris@909
|
71 @options[:assigns][:new_versions] = @new_versions
|
Chris@909
|
72 @options[:assigns][:current_versions] = @current_versions
|
Chris@909
|
73 end
|
Chris@909
|
74
|
Chris@909
|
75 # Returns a migration name. If the descriptive migration name based on the
|
Chris@909
|
76 # plugin names involved is shorter than 230 characters that one will be
|
Chris@909
|
77 # used. Otherwise a shorter name will be returned.
|
Chris@909
|
78 def build_migration_name
|
Chris@909
|
79 descriptive_migration_name.tap do |name|
|
Chris@909
|
80 name.replace short_migration_name if name.length > MAX_FILENAME_LENGTH
|
Chris@909
|
81 end
|
Chris@909
|
82 end
|
Chris@909
|
83
|
Chris@909
|
84 # Construct a unique migration name based on the plugins involved and the
|
Chris@909
|
85 # versions they should reach after this migration is run. The name constructed
|
Chris@909
|
86 # needs to be lowercase
|
Chris@909
|
87 def descriptive_migration_name
|
Chris@909
|
88 @plugins_to_migrate.map do |plugin|
|
Chris@909
|
89 "#{plugin.name}_to_version_#{@new_versions[plugin.name]}"
|
Chris@909
|
90 end.join("_and_").downcase
|
Chris@909
|
91 end
|
Chris@909
|
92
|
Chris@909
|
93 # Short migration name that will be used if the descriptive_migration_name
|
Chris@909
|
94 # exceeds 230 characters
|
Chris@909
|
95 def short_migration_name
|
Chris@909
|
96 'plugin_migrations'
|
Chris@909
|
97 end
|
Chris@909
|
98 end |