55require "fileutils"
66require "find"
77require "open3"
8+ # Required when this script runs outside the Homebrew style environment.
9+ # rubocop:disable Lint/RedundantRequireStatement
10+ require "pathname"
11+ # rubocop:enable Lint/RedundantRequireStatement
812require "yaml"
913
1014# This makes sense for a standalone script.
@@ -43,14 +47,7 @@ def git(*args)
4347stale_issues_workflow_yaml = ".github/workflows/stale-issues.yml"
4448zizmor_yml = ".github/zizmor.yml"
4549codeql_extensions_homebrew_actions_yml = ".github/codeql/extensions/homebrew-actions.yml"
46- brewsh_theme_paths = %w[
47- _includes
48- _layouts
49- _sass
50- assets/css
51- assets/img
52- bin/jekyll
53- ] . freeze
50+ brewsh_assets_url = "https://brew.sh"
5451
5552homebrew_docs = homebrew_repository_path /docs
5653homebrew_ruby_version =
@@ -282,28 +279,146 @@ def git(*args)
282279 end
283280end
284281
285- if brewsh_repository_path
282+ if brewsh_repository_path && repository_name != "brew.sh"
286283 theme_site_path = case repository_name
287- when "brew.sh" , " formulae.brew.sh"
284+ when "formulae.brew.sh"
288285 target_directory_path
289286 else
290287 target_docs_path = target_directory_path /docs
291288 target_docs_path if target_docs_path . directory?
292289 end
293290
294291 if theme_site_path
295- brewsh_theme_paths . each do |theme_path |
292+ shared_theme_paths = %w[ _includes _layouts ] . flat_map do |theme_path |
293+ source_path = brewsh_repository_path /theme_path
294+ next [ ] unless source_path . directory?
295+
296+ Find . find ( source_path . to_s ) . filter_map do |path |
297+ path = Pathname ( path )
298+ next if path . directory?
299+
300+ path . to_s . delete_prefix ( "#{ brewsh_repository_path } /" )
301+ end
302+ end
303+
304+ bin_jekyll = "bin/jekyll"
305+ shared_theme_paths << bin_jekyll if ( brewsh_repository_path /bin_jekyll ) . file?
306+
307+ read_front_matter = lambda do |path |
308+ next { } unless path . file?
309+
310+ contents = path . read
311+ front_matter = contents . match ( /\A ---\s *\n (.*?)\n ---\s *\n /m )
312+ next { } unless front_matter
313+
314+ YAML . safe_load ( front_matter [ 1 ] , permitted_classes : [ Symbol ] , aliases : true ) || { }
315+ rescue Psych ::Exception
316+ { }
317+ end
318+
319+ layout_path = lambda do |site_path , layout_name |
320+ %w[ html json md markdown ] . filter_map do |extension |
321+ path = site_path /"_layouts/#{ layout_name } .#{ extension } "
322+ path if path . file?
323+ end . first
324+ end
325+
326+ required_layouts = [ ]
327+ config_yml = theme_site_path /"_config.yml"
328+ if config_yml . file?
329+ config = YAML . safe_load ( config_yml . read , permitted_classes : [ Symbol ] , aliases : true ) || { }
330+ Array ( config [ "defaults" ] ) . each do |default |
331+ required_layouts << default . dig ( "values" , "layout" )
332+ end
333+ end
334+ has_posts = ( theme_site_path /"_posts" ) . directory?
335+
336+ Find . find ( theme_site_path . to_s ) do |path |
337+ path = Pathname ( path )
338+ relative_path = path . to_s . delete_prefix ( "#{ theme_site_path } /" )
339+ if path . directory?
340+ next Find . prune if %w[ .git .jekyll-cache _site assets vendor ] . include? ( path . basename . to_s )
341+ next Find . prune if relative_path . start_with? ( "_includes" , "_layouts" , "bin" )
342+
343+ next
344+ end
345+ next unless %w[ .html .md .markdown ] . include? ( path . extname )
346+
347+ required_layouts << read_front_matter . call ( path ) [ "layout" ]
348+ end
349+
350+ theme_paths = [ bin_jekyll ]
351+ seen_layouts = [ ]
352+ until required_layouts . empty?
353+ layout = required_layouts . shift
354+ next if layout . to_s . empty? || seen_layouts . include? ( layout )
355+
356+ seen_layouts << layout
357+ source_layout_path = layout_path . call ( brewsh_repository_path , layout )
358+ target_layout_path = layout_path . call ( theme_site_path , layout )
359+
360+ if source_layout_path
361+ theme_paths << source_layout_path . to_s . delete_prefix ( "#{ brewsh_repository_path } /" )
362+ required_layouts << read_front_matter . call ( source_layout_path ) [ "layout" ]
363+ elsif target_layout_path
364+ required_layouts << read_front_matter . call ( target_layout_path ) [ "layout" ]
365+ end
366+ end
367+
368+ required_includes = theme_paths . filter_map do |theme_path |
369+ next unless theme_path . start_with? ( "_layouts/" )
370+
371+ ( brewsh_repository_path /theme_path ) . read . scan ( /{%-?\s *include\s +([^"'\s %]+|"[^"]+"|'[^']+')/ ) . flatten
372+ end . flatten
373+
374+ until required_includes . empty?
375+ include_path = required_includes . shift
376+ include_path = include_path . delete_prefix ( "'" ) . delete_prefix ( '"' ) . delete_suffix ( "'" ) . delete_suffix ( '"' )
377+ next if include_path == "feed.html" && !has_posts
378+
379+ theme_path = "_includes/#{ include_path } "
380+ # `exclude?` is not available in all Ruby contexts this script may run in.
381+ # rubocop:disable Homebrew/NegateInclude
382+ next if theme_paths . include? ( theme_path ) || !shared_theme_paths . include? ( theme_path )
383+ # rubocop:enable Homebrew/NegateInclude
384+
385+ theme_paths << theme_path
386+ required_includes . concat (
387+ ( brewsh_repository_path /theme_path ) . read . scan ( /{%-?\s *include\s +([^"'\s %]+|"[^"]+"|'[^']+')/ ) . flatten ,
388+ )
389+ end
390+
391+ source_assets = theme_paths . filter_map do |theme_path |
392+ source_path = brewsh_repository_path /theme_path
393+ next unless source_path . file?
394+
395+ source_path . read . scan ( %r{"/assets/([^/]+)/} ) . flatten
396+ end . flatten . uniq
397+
398+ source_assets . each do |asset_type |
399+ target_path = theme_site_path /"assets/#{ asset_type } "
400+ if asset_type == "img"
401+ next unless target_path . directory?
402+
403+ target_path . children . select ( &:file? ) . each { |child | FileUtils . rm_f child }
404+ target_path . rmdir if target_path . children . empty?
405+ else
406+ FileUtils . rm_rf target_path
407+ end
408+ end
409+
410+ ( shared_theme_paths - theme_paths ) . each do |theme_path |
411+ FileUtils . rm_f theme_site_path /theme_path
412+ end
413+
414+ theme_paths . each do |theme_path |
296415 source_path = brewsh_repository_path /theme_path
297416 next unless source_path . exist?
298417
299418 if source_path . directory?
300419 Find . find ( source_path . to_s ) do |path |
301420 path = Pathname ( path )
302- if path . directory?
303- next Find . prune if theme_path == "assets/img" && path . basename . to_s == "blog"
304-
305- next
306- end
421+ next if path . directory?
307422
308423 relative_path = path . to_s . delete_prefix ( "#{ source_path } /" )
309424 target_path = theme_site_path /theme_path /relative_path
@@ -322,6 +437,50 @@ def git(*args)
322437 FileUtils . chmod source_path . stat . mode , target_path
323438 end
324439 end
440+
441+ %w[ _includes _layouts ] . each do |theme_path |
442+ target_path = theme_site_path /theme_path
443+ next unless target_path . directory?
444+
445+ Find . find ( target_path . to_s ) do |path |
446+ path = Pathname ( path )
447+ next if path . directory?
448+
449+ contents = path . read
450+ updated_contents = contents . gsub ( %r{\{ \{ \s *"/assets/(css|img)/([^"]+)"\s *\| \s *relative_url\s *\} \} } ) do
451+ "#{ brewsh_assets_url } /assets/#{ Regexp . last_match ( 1 ) } /#{ Regexp . last_match ( 2 ) } "
452+ end
453+ unless has_posts
454+ updated_contents = updated_contents . gsub (
455+ /
456+ \n \s *\{ % if site\. feed and site\. posts\. size > 0 -%\}
457+ \n \s *\{ % include feed\. html -%\}
458+ \n \s *\{ % endif -%\}
459+ /x ,
460+ "" ,
461+ )
462+ end
463+ path . write updated_contents if contents != updated_contents
464+ end
465+ end
466+
467+ Find . find ( theme_site_path . to_s ) do |path |
468+ path = Pathname ( path )
469+ relative_path = path . to_s . delete_prefix ( "#{ theme_site_path } /" )
470+ if path . directory?
471+ next Find . prune if %w[ .git .jekyll-cache _site vendor ] . include? ( path . basename . to_s )
472+ next Find . prune if relative_path . start_with? ( "assets" )
473+
474+ next
475+ end
476+ next unless [ ".html" , ".md" , ".markdown" , ".yml" , ".yaml" ] . include? ( path . extname )
477+
478+ contents = path . read
479+ updated_contents = contents . gsub ( %r{(:\s *["']?)/assets/img/([^/"'\s ]+)(["']?)} ) do
480+ "#{ Regexp . last_match ( 1 ) } #{ brewsh_assets_url } /assets/img/#{ Regexp . last_match ( 2 ) } #{ Regexp . last_match ( 3 ) } "
481+ end
482+ path . write updated_contents if contents != updated_contents
483+ end
325484 end
326485end
327486
0 commit comments