1
1
# frozen_string_literal: true
2
2
3
- require_relative "diff/version"
4
- require_relative "diff/file_tracker"
5
3
require "rails"
6
- require "thor"
7
4
require "diffy"
8
5
require "fileutils"
9
6
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"
10
13
11
14
module Rails
12
15
module Diff
13
- class Error < StandardError ; end
14
-
15
- RAILS_REPO = "https://github.com/rails/rails.git"
16
16
CACHE_DIR = File . expand_path ( "#{ ENV [ "HOME" ] } /.rails-diff/cache" )
17
- RAILSRC_PATH = "#{ ENV [ "HOME" ] } /.railsrc"
18
17
19
18
class << self
20
19
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
23
22
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 " )
25
26
end
26
27
27
28
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
31
32
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 ) }
34
35
. join ( "\n \n " )
35
36
end
36
37
37
- private
38
-
39
- def system! ( *cmd , abort : true )
38
+ def system! ( *cmd , logger :, abort : true )
40
39
_ , stderr , status = Open3 . capture3 ( *cmd )
41
-
42
- debug cmd . join ( " " )
43
-
40
+ logger . debug ( cmd . join ( " " ) )
44
41
if status . success?
45
42
true
46
43
elsif abort
47
- $stderr . puts " \e [1;31mCommand failed:\e [0m #{ cmd . join ( ' ' ) } "
44
+ logger . error ( "Command failed:" , cmd . join ( " " ) )
48
45
abort stderr
49
46
else
50
47
false
51
48
end
52
49
end
53
50
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
109
52
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 )
112
55
return if diff . empty?
113
56
114
57
header = "#{ file } diff:"
115
58
[ header , "=" * header . size , diff ] . join ( "\n " )
116
59
end
117
60
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 )
128
62
rails_file = File . join ( template_app_path , file )
129
63
repo_file = File . join ( Dir . pwd , file )
130
64
@@ -135,129 +69,9 @@ def diff_file(file)
135
69
rails_file ,
136
70
repo_file ,
137
71
context : 2 ,
138
- source : ' files'
72
+ source : " files"
139
73
) . to_s ( :color ) . chomp
140
74
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
261
75
end
262
76
end
263
77
end
0 commit comments