Skip to content

Commit 2abd165

Browse files
committed
Internal refactoring
1 parent ac4064f commit 2abd165

File tree

11 files changed

+564
-321
lines changed

11 files changed

+564
-321
lines changed

lib/rails/diff.rb

Lines changed: 24 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,64 @@
11
# frozen_string_literal: true
22

3-
require_relative "diff/version"
4-
require_relative "diff/file_tracker"
53
require "rails"
6-
require "thor"
74
require "diffy"
85
require "fileutils"
96
require "open3"
7+
require_relative "diff/cli"
8+
require_relative "diff/file_tracker"
9+
require_relative "diff/logger"
10+
require_relative "diff/rails_app_generator"
11+
require_relative "diff/rails_repo"
12+
require_relative "diff/version"
1013

1114
module Rails
1215
module Diff
13-
class Error < StandardError; end
14-
15-
RAILS_REPO = "https://github.com/rails/rails.git"
1616
CACHE_DIR = File.expand_path("#{ENV["HOME"]}/.rails-diff/cache")
17-
RAILSRC_PATH = "#{ENV["HOME"]}/.railsrc"
1817

1918
class << self
2019
def file(*files, no_cache: false, commit: nil, new_app_options: nil)
21-
clear_cache if no_cache
22-
ensure_template_app_exists(commit, new_app_options)
20+
app_generator = RailsAppGenerator.new(commit:, new_app_options:, no_cache:)
21+
app_generator.create_template_app
2322

24-
files.filter_map { |it| diff_with_header(it) }.join("\n")
23+
files
24+
.filter_map { |it| diff_with_header(it, app_generator.template_app_path) }
25+
.join("\n")
2526
end
2627

2728
def generated(generator_name, *args, no_cache: false, skip: [], only: [], commit: nil, new_app_options: nil)
28-
clear_cache if no_cache
29-
ensure_template_app_exists(commit, new_app_options)
30-
install_app_dependencies
29+
app_generator = RailsAppGenerator.new(commit:, new_app_options:, no_cache:)
30+
app_generator.create_template_app
31+
app_generator.install_app_dependencies
3132

32-
generated_files(generator_name, *args, skip, only)
33-
.map { |it| diff_with_header(it) }
33+
app_generator.run_generator(generator_name, *args, skip, only)
34+
.map { |it| diff_with_header(it, app_generator.template_app_path) }
3435
.join("\n\n")
3536
end
3637

37-
private
38-
39-
def system!(*cmd, abort: true)
38+
def system!(*cmd, logger:, abort: true)
4039
_, stderr, status = Open3.capture3(*cmd)
41-
42-
debug cmd.join(" ")
43-
40+
logger.debug(cmd.join(" "))
4441
if status.success?
4542
true
4643
elsif abort
47-
$stderr.puts "\e[1;31mCommand failed:\e[0m #{cmd.join(' ')}"
44+
logger.error("Command failed:", cmd.join(" "))
4845
abort stderr
4946
else
5047
false
5148
end
5249
end
5350

54-
def info(message)
55-
puts "\e[1;34minfo:\e[0m\t#{message}"
56-
end
57-
58-
def debug(message)
59-
return unless ENV["DEBUG"]
60-
61-
puts "\e[1;33mdebug:\e[0m\t#{message}"
62-
end
63-
64-
def clear_cache
65-
info "Clearing cache"
66-
FileUtils.rm_rf(CACHE_DIR)
67-
end
68-
69-
def ensure_template_app_exists(commit, new_app_options)
70-
FileUtils.mkdir_p(CACHE_DIR)
71-
@new_app_options = new_app_options
72-
@commit = commit || latest_commit
73-
return if cached_app?
74-
75-
create_new_rails_app
76-
end
77-
78-
def template_app_path
79-
@template_app_path ||= File.join(CACHE_DIR, "rails-#{commit.first(10)}", rails_new_options_hash, app_name)
80-
end
81-
82-
def rails_path
83-
@rails_path ||= begin
84-
File.join(CACHE_DIR, "rails").tap do |path|
85-
unless File.exist?(path)
86-
info "Cloning Rails repository"
87-
system!("git", "clone", "--depth", "1", RAILS_REPO, path)
88-
end
89-
end
90-
end
91-
end
92-
93-
def railsrc_options
94-
return @railsrc_options if defined?(@railsrc_options)
95-
96-
@railsrc_options = File.read(RAILSRC_PATH).lines if File.exist?(RAILSRC_PATH)
97-
end
98-
99-
def app_name = @app_name ||= File.basename(Dir.pwd)
100-
101-
def generated_files(generator_name, *args, skip, only)
102-
Dir.chdir(template_app_path) do
103-
system!("bin/rails", "destroy", generator_name, *args)
104-
info "Running generator: rails generate #{generator_name} #{args.join(' ')}"
105-
FileTracker.new.track_new_files(template_app_path, skip, only) { system!("bin/rails", "generate", generator_name, *args) }
106-
.map { |it| it.delete_prefix("#{template_app_path}/") }
107-
end
108-
end
51+
private
10952

110-
def diff_with_header(file)
111-
diff = diff_file(file)
53+
def diff_with_header(file, template_app_path)
54+
diff = diff_file(file, template_app_path)
11255
return if diff.empty?
11356

11457
header = "#{file} diff:"
11558
[header, "=" * header.size, diff].join("\n")
11659
end
11760

118-
def install_app_dependencies
119-
Dir.chdir(template_app_path) do
120-
unless system!("bundle check", abort: false)
121-
info "Installing application dependencies"
122-
system!("bundle install")
123-
end
124-
end
125-
end
126-
127-
def diff_file(file)
61+
def diff_file(file, template_app_path)
12862
rails_file = File.join(template_app_path, file)
12963
repo_file = File.join(Dir.pwd, file)
13064

@@ -135,129 +69,9 @@ def diff_file(file)
13569
rails_file,
13670
repo_file,
13771
context: 2,
138-
source: 'files'
72+
source: "files"
13973
).to_s(:color).chomp
14074
end
141-
142-
def cached_app?
143-
File.exist?(template_app_path) && !out_of_date_rails?
144-
end
145-
146-
def out_of_date_rails?
147-
return true unless File.exist?(rails_path)
148-
149-
Dir.chdir(rails_path) do
150-
system!("git fetch origin main")
151-
current = `git rev-parse HEAD`.strip
152-
latest = `git rev-parse origin/main`.strip
153-
154-
if current != latest
155-
FileUtils.rm_rf(rails_path)
156-
return true
157-
end
158-
end
159-
160-
false
161-
end
162-
163-
def create_new_rails_app
164-
Dir.chdir(rails_path) do
165-
checkout_rails
166-
generate_app
167-
end
168-
end
169-
170-
def generate_app
171-
Dir.chdir("railties") do
172-
unless system!("bundle check", abort: false)
173-
info "Installing Rails dependencies"
174-
system!("bundle install")
175-
end
176-
177-
if railsrc_options
178-
info "Using default options from #{RAILSRC_PATH}:\n\t > #{railsrc_options.join(' ')}"
179-
end
180-
181-
info "Generating new Rails application\n\t > #{rails_new_command.join(' ')}"
182-
system!(*rails_new_command)
183-
end
184-
end
185-
186-
def checkout_rails
187-
info "Checking out Rails (at commit #{commit[0..6]})"
188-
system!("git", "checkout", commit)
189-
end
190-
191-
def commit = @commit
192-
193-
def new_app_options = @new_app_options
194-
195-
def latest_commit
196-
Dir.chdir(rails_path) do
197-
`git rev-parse origin/main`.strip
198-
end
199-
end
200-
201-
def rails_new_command = @rails_new_command ||= [
202-
"bundle",
203-
"exec",
204-
"rails",
205-
"new",
206-
template_app_path,
207-
"--main",
208-
"--skip-bundle",
209-
"--force",
210-
"--quiet",
211-
*rails_new_options
212-
]
213-
214-
def rails_new_options = @rails_new_options ||= [*new_app_options, *railsrc_options].compact
215-
216-
def rails_new_options_hash = Digest::MD5.hexdigest(rails_new_options.join(" "))
217-
end
218-
219-
class CLI < Thor
220-
class_option :no_cache, type: :boolean, desc: "Clear cache before running", aliases: ["--clear-cache"]
221-
class_option :fail_on_diff, type: :boolean, desc: "Fail if there are differences"
222-
class_option :commit, type: :string, desc: "Compare against a specific commit"
223-
class_option :new_app_options, type: :string, desc: "Options to pass to the rails new command"
224-
class_option :debug, type: :boolean, desc: "Print debug information", aliases: ["-d"]
225-
226-
def self.exit_on_failure? = true
227-
228-
desc "file FILE [FILE ...]", "Compare one or more files from your repository with Rails' generated version"
229-
def file(*files)
230-
abort "Please provide at least one file to compare" if files.empty?
231-
ENV["DEBUG"] = "true" if options[:debug]
232-
233-
diff = Rails::Diff.file(*files, no_cache: options[:no_cache], commit: options[:commit], new_app_options: options[:new_app_options])
234-
return if diff.empty?
235-
236-
options[:fail] ? abort(diff) : puts(diff)
237-
end
238-
239-
desc "generated GENERATOR [args]", "Compare files that would be created by a Rails generator"
240-
option :skip, type: :array, desc: "Skip specific files or directories", aliases: ["-s"], default: []
241-
option :only, type: :array, desc: "Only include specific files or directories", aliases: ["-o"], default: []
242-
def generated(generator_name, *args)
243-
ENV["DEBUG"] = "true" if options[:debug]
244-
diff = Rails::Diff.generated(generator_name,
245-
*args,
246-
no_cache: options[:no_cache],
247-
skip: options[:skip],
248-
only: options[:only],
249-
commit: options[:commit],
250-
new_app_options: options[:new_app_options])
251-
return if diff.empty?
252-
253-
options[:fail] ? abort(diff) : puts(diff)
254-
end
255-
256-
map %w[--version -v] => :__version
257-
desc "--version, -v", "print the version"
258-
def __version
259-
puts VERSION
260-
end
26175
end
26276
end
26377
end

lib/rails/diff/cli.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
require "thor"
2+
3+
module Rails
4+
module Diff
5+
class CLI < Thor
6+
class_option :no_cache, type: :boolean, desc: "Clear cache before running", aliases: ["--clear-cache"]
7+
class_option :fail_on_diff, type: :boolean, desc: "Fail if there are differences"
8+
class_option :commit, type: :string, desc: "Compare against a specific commit"
9+
class_option :new_app_options, type: :string, desc: "Options to pass to the rails new command"
10+
class_option :debug, type: :boolean, desc: "Print debug information", aliases: ["-d"]
11+
12+
def self.exit_on_failure? = true
13+
14+
desc "file FILE [FILE ...]", "Compare one or more files from your repository with Rails' generated version"
15+
def file(*files)
16+
abort "Please provide at least one file to compare" if files.empty?
17+
ENV["DEBUG"] = "true" if options[:debug]
18+
19+
diff = Rails::Diff.file(
20+
*files,
21+
no_cache: options[:no_cache],
22+
commit: options[:commit],
23+
new_app_options: options[:new_app_options]
24+
)
25+
return if diff.empty?
26+
27+
options[:fail] ? abort(diff) : puts(diff)
28+
end
29+
30+
desc "generated GENERATOR [args]", "Compare files that would be created by a Rails generator"
31+
option :skip, type: :array, desc: "Skip specific files or directories", aliases: ["-s"], default: []
32+
option :only, type: :array, desc: "Only include specific files or directories", aliases: ["-o"], default: []
33+
def generated(generator_name, *args)
34+
ENV["DEBUG"] = "true" if options[:debug]
35+
diff = Rails::Diff.generated(
36+
generator_name,
37+
*args,
38+
no_cache: options[:no_cache],
39+
skip: options[:skip],
40+
only: options[:only],
41+
commit: options[:commit],
42+
new_app_options: options[:new_app_options]
43+
)
44+
return if diff.empty?
45+
46+
options[:fail] ? abort(diff) : puts(diff)
47+
end
48+
49+
map %w[--version -v] => :__version
50+
desc "--version, -v", "print the version"
51+
def __version
52+
puts VERSION
53+
end
54+
end
55+
end
56+
end

0 commit comments

Comments
 (0)