Class: Enginery::Migrator
- Inherits:
-
Object
- Object
- Enginery::Migrator
- Includes:
- Helpers
- Defined in:
- lib/enginery/migrator.rb,
app/migrations/tracking_table/Sequel.rb,
app/migrations/tracking_table/DataMapper.rb,
app/migrations/tracking_table/ActiveRecord.rb
Defined Under Namespace
Classes: TracksMigrator, TracksModel
Constant Summary collapse
- TIME_FORMAT =
'%Y-%m-%d_%H-%M-%S'.freeze
- NAME_REGEXP =
/\A(\d+)\.(\d+\-\d+\-\d+_\d+\-\d+\-\d+)\.(.*)#{Regexp.escape MIGRATION_SUFFIX}\Z/.freeze
Instance Method Summary collapse
-
#initialize(dst_root, setups = {}) ⇒ Migrator
constructor
A new instance of Migrator.
- #last_run(file) ⇒ Object
-
#list ⇒ Object
list available migrations with date of last run, if any.
-
#new(name) ⇒ Object
generate new migration.
- #outstanding_migrations(vector) ⇒ Object
-
#run(vector, file, force_run = nil) ⇒ Object
-
validate migration file name - apply migration in given direction if migration was not previously performed in given direction or :force option given - create a track in TRACKING_TABLE so on consequent requests we may know whether migration was already performed.
-
-
#serials_to_files(vector, *serials) ⇒ Object
convert given range or a single migration into files to be run ex: 1-5 will run migrations from one to 5 inclusive 1 2 4 will run 1st, 2nd, and 4th migrations 2 will run only 2nd migration.
Methods included from Helpers
#activerecord_associations, #app_config, #app_controllers, #app_models, #boot_app, #controller_exists?, #datamapper_associations, #dst_path, extract_setup, fail, #fail_unless_in_app_folder!, fail_verbosely, #in_app_folder?, #load_boot_rb, #migrations_by_model, #model_exists?, o, parse_input, #routes_by_controller, #sequel_associations, #src_path, #unrootify, #valid_controller?, valid_db_type?, valid_engine?, valid_orm?, #valid_route?, valid_server?, validate_constant_name, #validate_route_name, #view_setups_for
Constructor Details
#initialize(dst_root, setups = {}) ⇒ Migrator
Returns a new instance of Migrator.
8 9 10 11 12 13 14 15 |
# File 'lib/enginery/migrator.rb', line 8 def initialize dst_root, setups = {} @dst_root, @setups = dst_root, setups @migrations = Dir[dst_path(:migrations, '**/*%s' % MIGRATION_SUFFIX)].inject([]) do |map,f| step, time, name = File.basename(f).scan(NAME_REGEXP).flatten step && time && name && map << [step.to_i, time, name, f.sub(dst_path.migrations, '')] map end.sort {|a,b| a.first <=> b.first}.freeze end |
Instance Method Details
#last_run(file) ⇒ Object
128 129 130 131 132 |
# File 'lib/enginery/migrator.rb', line 128 def last_run file create_tracking_table_if_needed return unless track = track_exists?(file) [track.vector, track.performed_at] end |
#list ⇒ Object
list available migrations with date of last run, if any
107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/enginery/migrator.rb', line 107 def list create_tracking_table_if_needed o indent('--'), '-=---' @migrations.each do |(step,time,name,file)| track = track_exists?(File.basename(file)) last_perform = track ? '%s on %s' % [track.vector, track.performed_at] : 'none' o indent(step), ' : ', name o indent('created at'), ' : ', DateTime.strptime(time, TIME_FORMAT).rfc2822 o indent('last performed'), ' : ', last_perform o indent('--'), '-=---' end end |
#new(name) ⇒ Object
generate new migration. it will create a [n]..[name].rb migration file in base/migrations/ and column_transitions.yml file in base/migrations/track/ migration file will contain “up” and “down” sections. column_transitions file will keep track of column type changes.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/enginery/migrator.rb', line 23 def new name (name.nil? || name.empty?) && fail("Please provide migration name via second argument") (name =~ /[^\w|\d|\-|\.|\:]/) && fail("Migration name can contain only alphanumerics, dashes, semicolons and dots") @migrations.any? {|m| m[2] == name} && fail('"%s" migration already exists' % name) max = (@migrations.max {|m| m.first}||[0]).first model = @setups[:create_table] || @setups[:update_table] context = {model: model, name: name, step: max + 1} [:create_table, :update_table].each do |o| context[o] = (m = constant_defined?(@setups[o])) ? model_to_table(m) : nil end table = context[:create_table] || context[:update_table] || fail('No model provided or provided one does not exists!') [:create_columns, :update_columns].each do |o| context[o] = transitions(table, (@setups[o]||[]).map {|(n,t)| [n, opted_column_type(t)]}) end context[:rename_columns] = @setups[:rename_columns]||[] engine = Tenjin::Engine.new(path: [src_path.migrations], cache: false) source_code = engine.render('%s.erb' % guess_orm, context.merge(context: context)) o o '--- %s model - generating "%s" migration ---' % [model, name] o o ' Serial Number: %s' % context[:step] o time = Time.now.strftime(TIME_FORMAT) path = dst_path(:migrations, class_to_route(model)) FileUtils.mkdir_p(path) file = File.join(path, [context[:step], time, name, 'rb']*'.') write_file file, source_code output_source_code source_code.split("\n") name end |
#outstanding_migrations(vector) ⇒ Object
120 121 122 123 124 125 126 |
# File 'lib/enginery/migrator.rb', line 120 def outstanding_migrations vector create_tracking_table_if_needed serials = @migrations.inject([]) do |l,(step,time,name,file)| track_exists?(File.basename(file), vector) ? l : l.push(step) end serials_to_files(vector, *serials) end |
#run(vector, file, force_run = nil) ⇒ Object
-
validate migration file name
-
apply migration in given direction if migration was not previously performed in given direction or :force option given
-
create a track in TRACKING_TABLE so on consequent requests we may know whether migration was already performed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/enginery/migrator.rb', line 86 def run vector, file, force_run = nil vector = validate_vector(vector) (migration = @migrations.find {|m| m.last == file}) || fail('"%s" is not a valid migration file' % file) create_tracking_table_if_needed track = track_exists?(file, vector) if track && !force_run o o '*** Skipping "%s: %s" migration ***' % [migration[0], migration[2]] o ' It was already performed %s on %s' % [track.vector.upcase, track.performed_at] o ' Use :force option to run it anyway - enginery m:%s:force ...' % vector o return end apply!(migration, vector) && persist_track(file, vector) end |
#serials_to_files(vector, *serials) ⇒ Object
convert given range or a single migration into files to be run ex: 1-5 will run migrations from one to 5 inclusive
1 2 4 will run 1st, 2nd, and 4th migrations
2 will run only 2nd migration
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/enginery/migrator.rb', line 64 def serials_to_files vector, *serials vector = validate_vector(vector) serials.map do |serial| if serial =~ /\-/ a, z = serial.split('-') (a..z).to_a else serial end end.flatten.map do |e| @migrations.find {|m| m.first == e.to_i} || fail('Wrong range provided. "%s" is not a recognized migration step' % e) end.sort do |a,b| vector == :up ? a.first <=> b.first : b.first <=> a.first end.map(&:last) end |