From e371f45984723d185fe98e5d6c35ad145d7d9304 Mon Sep 17 00:00:00 2001 From: Jacob Crofts Date: Sun, 8 Mar 2020 12:26:22 -0700 Subject: [PATCH 1/3] Make dependency requirements more permissive (>= instead of ~>) --- jack-core/src/Gemfile | 4 ++-- jack-core/src/Gemfile.lock | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/jack-core/src/Gemfile b/jack-core/src/Gemfile index d36c5731..3f7f5f41 100644 --- a/jack-core/src/Gemfile +++ b/jack-core/src/Gemfile @@ -1,4 +1,4 @@ source "http://rubygems.org" -gem "activesupport", "~> 4.1" -gem "i18n", "~> 0.9" +gem "activesupport", ">= 4.1" +gem "i18n", ">= 0.9" gem 'fattr' diff --git a/jack-core/src/Gemfile.lock b/jack-core/src/Gemfile.lock index 2df79232..5f633eae 100644 --- a/jack-core/src/Gemfile.lock +++ b/jack-core/src/Gemfile.lock @@ -1,29 +1,27 @@ GEM remote: http://rubygems.org/ specs: - activesupport (4.2.5) - i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) + activesupport (5.2.4.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - concurrent-ruby (1.0.5) + concurrent-ruby (1.1.6) fattr (2.4.0) - i18n (0.9.1) + i18n (1.8.2) concurrent-ruby (~> 1.0) - json (1.8.6) - minitest (5.10.3) + minitest (5.14.0) thread_safe (0.3.6) - tzinfo (1.2.4) + tzinfo (1.2.6) thread_safe (~> 0.1) PLATFORMS ruby DEPENDENCIES - activesupport (~> 4.1) + activesupport (>= 4.1) fattr - i18n (~> 0.9) + i18n (>= 0.9) BUNDLED WITH - 1.16.1 + 1.17.2 From 2e2d0da37cc03f88b6a9ebf7095fef7420b4c8a1 Mon Sep 17 00:00:00 2001 From: Jacob Crofts Date: Sun, 8 Mar 2020 12:35:13 -0700 Subject: [PATCH 2/3] Add a hack to support Rails 4+ --- jack-core/src/rb/rails_3_to_5_translator.rb | 83 +++++++++++++++++++++ jack-core/src/rb/requires.rb | 1 + jack-core/src/rb/schema_rb_parser.rb | 14 +++- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 jack-core/src/rb/rails_3_to_5_translator.rb diff --git a/jack-core/src/rb/rails_3_to_5_translator.rb b/jack-core/src/rb/rails_3_to_5_translator.rb new file mode 100644 index 00000000..74e0da0f --- /dev/null +++ b/jack-core/src/rb/rails_3_to_5_translator.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +# Jack is designed for a version of Rails 3, which was end-of-lifed +# back in June of 2016. When Jack reads from the ActiveRecord +# schema, it does not account for various changes in the schema +# format that have been introduced subsequently: +# 1. add_index(table, columns, opts={}) was replaced by +# t.index(columns, opts={}) within a create_table block +# 2. t.integer(column, limit: 8) was replaced by t.bigint(column, opts={}) +# +# Because there aren't very many schema changes and they are relatively +# simple, it seemed to Jacob that the laziest way to offer compatibility +# between Jack and newer versions of Rails is to programmatically +# translate Rails 4+ schemas into Rails 3 schemas and then run Jack +# as usual. He at least tried to update Jack to Rails 5, but it soon +# became clear that doing so would be more of a struggle than the +# aforementioned solution, and time happens to be of the essence right now. +# Future maintainers of this project should not hesitate to update Jack +# properly as time allows. +class Rails3To5Translator + def initialize(schema_rb_path) + @schema_rb_path = schema_rb_path + end + + def translate + new_contents = '' + index_calls_by_table_name = hash_with_empty_arrays_as_new_values + this_table_name = nil + nesting_degree = 0 + + File.readlines(@schema_rb_path).each do |line| + # comments and empty lines + next if line.strip.start_with?('#') || line.strip == '' + + if line.strip.start_with?('create_table') + # remember which table we're operating on + match = /create_table \"(.*?)\"/.match(line) + this_table_name = match[1] + nesting_degree += 1 + + elsif line.end_with?("do\n") || /do \|.*\|/.match(line) + # remember how far nested we are in terms of do/end blocks + nesting_degree += 1 + + elsif line.strip.start_with?('end') + # check if we have reached the final "end" in the file + # and, if so, replace it with the add_index calls we need + nesting_degree -= 1 + + if nesting_degree.zero? + index_calls_by_table_name.each do |table_name, index_calls| + index_calls.each do |index_call| + new_contents += " add_index [\"#{table_name}\"], #{index_call}\n" + end + end + end + + elsif /\.bigint/.match(line) + # case 1 described in the top level comment + line.sub!('.bigint', '.integer') + line.sub!("\n", ", limit: 8\n") + + elsif /\.index/.match(line) + # case 2 described in the top level comment + method_parameters = /\.index (.*?)\n/.match(line)[1] + index_calls_by_table_name[this_table_name].push(method_parameters) + next + end + + new_contents += line + end + + new_contents + end + + private + + def hash_with_empty_arrays_as_new_values + Hash.new do |hash, unrecognized_key| + hash[unrecognized_key] = [] + end + end +end diff --git a/jack-core/src/rb/requires.rb b/jack-core/src/rb/requires.rb index c170224c..ae1a5544 100644 --- a/jack-core/src/rb/requires.rb +++ b/jack-core/src/rb/requires.rb @@ -16,5 +16,6 @@ require File.expand_path(File.dirname(__FILE__) + "/database_defn") require File.expand_path(File.dirname(__FILE__) + "/project_defn") require File.expand_path(File.dirname(__FILE__) + "/schema_rb_parser") +require File.expand_path(File.dirname(__FILE__) + "/rails_3_to_5_translator") require File.expand_path(File.dirname(__FILE__) + "/models_dir_processor") require File.expand_path(File.dirname(__FILE__) + "/template_processor") diff --git a/jack-core/src/rb/schema_rb_parser.rb b/jack-core/src/rb/schema_rb_parser.rb index 13af5ae1..9bc4ce50 100644 --- a/jack-core/src/rb/schema_rb_parser.rb +++ b/jack-core/src/rb/schema_rb_parser.rb @@ -18,6 +18,7 @@ module FromHash def from_hash(ops) + ops.delete(:options) ops.each do |k,v| send("#{k}=",v) end @@ -124,9 +125,20 @@ def to_h class SchemaRbParser def self.parse(schema_rb, ignored_tables = []) - load schema_rb + translated_contents = Rails3To5Translator.new(schema_rb).translate + old_filename = schema_rb.split('/').last + new_schema_rb = schema_rb.sub(old_filename, 'TEMP_rails_3_compatible_schema.rb') + FileUtils.touch(new_schema_rb) + File.write(new_schema_rb, translated_contents) + load_new_schema(new_schema_rb, ignored_tables) + end + + def self.load_new_schema(translated_schema_rb, ignored_tables) + load translated_schema_rb defns = $schema.tables.map(&:to_model_defn).compact.reject { |x| ignored_tables.include?(x.table_name) } [defns, $schema.version.to_s] + ensure + FileUtils.rm(translated_schema_rb) end end From 44430f04e4508ca4767c724ae58c7abb959baca6 Mon Sep 17 00:00:00 2001 From: Jacob Crofts Date: Sun, 8 Mar 2020 23:18:51 -0700 Subject: [PATCH 3/3] Add Dockerfile with example usage --- jack-core/src/Dockerfile | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 jack-core/src/Dockerfile diff --git a/jack-core/src/Dockerfile b/jack-core/src/Dockerfile new file mode 100644 index 00000000..1264421b --- /dev/null +++ b/jack-core/src/Dockerfile @@ -0,0 +1,17 @@ +# Use an official Ruby runtime as a parent image +FROM ruby:2.3.0 + +# Set the working directory to /app +WORKDIR /app + +# Copy the current directory contents into the container at /app +COPY . /app + +RUN bundle install + +# The consumer is expected to provide two additional arguments: +# 1. the path to the Jack config file +# 2. the output directory +# +# example usage: docker run -w /app -v $(pwd):/app/temp --rm jack temp/jack_config.yml temp/jack +ENTRYPOINT ["ruby", "./rb/jack.rb"]