11# typed: strict
22# frozen_string_literal: true
33
4+ require "open3"
5+
46module Tapioca
57 module Commands
68 # @abstract
@@ -26,7 +28,8 @@ class AbstractDsl < CommandWithoutTracker
2628 #| ?app_root: String,
2729 #| ?halt_upon_load_error: bool,
2830 #| ?compiler_options: Hash[String, untyped],
29- #| ?lsp_addon: bool
31+ #| ?lsp_addon: bool,
32+ #| ?max_diff_lines: Integer
3033 #| ) -> void
3134 def initialize (
3235 requested_constants :,
@@ -46,7 +49,8 @@ def initialize(
4649 app_root : "." ,
4750 halt_upon_load_error : true ,
4851 compiler_options : { } ,
49- lsp_addon : false
52+ lsp_addon : false ,
53+ max_diff_lines : DEFAULT_MAX_DIFF_LINES
5054 )
5155 @requested_constants = requested_constants
5256 @requested_paths = requested_paths
@@ -66,6 +70,7 @@ def initialize(
6670 @skip_constant = skip_constant
6771 @compiler_options = compiler_options
6872 @lsp_addon = lsp_addon
73+ @max_diff_lines = max_diff_lines
6974
7075 super ( )
7176 end
@@ -240,9 +245,9 @@ def compile_dsl_rbi(constant_name, rbi, outpath: @outpath, quiet: false)
240245
241246 #: (Pathname dir) -> void
242247 def perform_dsl_verification ( dir )
243- diff = verify_dsl_rbi ( tmp_dir : dir )
248+ diff , diff_output = verify_dsl_rbi ( tmp_dir : dir )
244249
245- report_diff_and_exit_if_out_of_date ( diff , :dsl )
250+ report_diff_and_exit_if_out_of_date ( diff , diff_output , :dsl )
246251 ensure
247252 FileUtils . remove_entry ( dir )
248253 end
@@ -264,9 +269,10 @@ def dsl_rbi_filename(constant_name)
264269 @outpath / "#{ underscore ( constant_name ) } .rbi"
265270 end
266271
267- #: (tmp_dir: Pathname) -> Hash[String, Symbol]
272+ #: (tmp_dir: Pathname) -> [ Hash[String, Symbol], String ]
268273 def verify_dsl_rbi ( tmp_dir :)
269274 diff = { }
275+ diff_output = String . new
270276
271277 existing_rbis = rbi_files_in ( @outpath )
272278 new_rbis = rbi_files_in ( tmp_dir )
@@ -275,12 +281,14 @@ def verify_dsl_rbi(tmp_dir:)
275281
276282 added_files . each do |file |
277283 diff [ file ] = :added
284+ diff_output << file_diff ( file , File ::NULL , tmp_dir / file )
278285 end
279286
280287 removed_files = ( existing_rbis - new_rbis )
281288
282289 removed_files . each do |file |
283290 diff [ file ] = :removed
291+ diff_output << file_diff ( file , @outpath / file , File ::NULL )
284292 end
285293
286294 common_files = ( existing_rbis & new_rbis )
@@ -291,9 +299,30 @@ def verify_dsl_rbi(tmp_dir:)
291299
292300 changed_files . each do |file |
293301 diff [ file ] = :changed
302+ diff_output << file_diff ( file , @outpath / file , tmp_dir / file )
294303 end
295304
296- diff
305+ [ diff , diff_output ]
306+ end
307+
308+ #: (Pathname filename, String | Pathname old_path, String | Pathname new_path) -> String
309+ def file_diff ( filename , old_path , new_path )
310+ stdout , stderr , status = Open3 . capture3 (
311+ "diff" ,
312+ "-u" ,
313+ "--label" ,
314+ filename . to_s ,
315+ "--label" ,
316+ filename . to_s ,
317+ old_path . to_s ,
318+ new_path . to_s ,
319+ )
320+ raise stderr . chomp unless [ 0 , 1 ] . include? ( status . exitstatus )
321+
322+ stdout
323+ rescue => e
324+ say_error ( "Failed to create #{ filename } diff. #{ e . message } " , :red )
325+ ""
297326 end
298327
299328 #: (Symbol cause, Array[String] files) -> String
@@ -305,16 +334,25 @@ def build_error_for_files(cause, files)
305334 " File(s) #{ cause } :\n - #{ filenames } "
306335 end
307336
308- #: (Hash[String, Symbol] diff, Symbol command) -> void
309- def report_diff_and_exit_if_out_of_date ( diff , command )
337+ #: (Hash[String, Symbol] diff, String diff_output, Symbol command) -> void
338+ def report_diff_and_exit_if_out_of_date ( diff , diff_output , command )
310339 if diff . empty?
311340 say ( "Nothing to do, all RBIs are up-to-date." )
312341 else
313342 reasons = diff . group_by ( &:last ) . sort . map do |cause , diff_for_cause |
314343 build_error_for_files ( cause , diff_for_cause . map ( &:first ) )
315344 end . join ( "\n " )
316345
317- raise Tapioca ::Error , <<~ERROR
346+ diff_lines = diff_output . lines . count
347+ file_diff = if diff_lines . between? ( 1 , @max_diff_lines )
348+ "#{ set_color ( "Diff:" , :red ) } \n #{ diff_output . chomp } "
349+ elsif diff_lines > @max_diff_lines
350+ set_color ( "Diff not displayed as it exceeds #{ @max_diff_lines } lines" , :red )
351+ else
352+ ""
353+ end
354+
355+ raise Tapioca ::Error , <<~ERROR . rstrip
318356 #{ set_color ( "RBI files are out-of-date. In your development environment, please run:" , :green ) }
319357 #{ set_color ( "`#{ default_command ( command ) } `" , :green , :bold ) }
320358 #{ set_color ( "Once it is complete, be sure to commit and push any changes" , :green ) }
@@ -323,6 +361,8 @@ def report_diff_and_exit_if_out_of_date(diff, command)
323361
324362 #{ set_color ( "Reason:" , :red ) }
325363 #{ reasons }
364+
365+ #{ file_diff }
326366 ERROR
327367 end
328368 end
0 commit comments