Skip to content

Commit f424f17

Browse files
committed
Reference brew.sh theme assets
- Keep shared image assets in `brew.sh` instead of copying them to docs sites. - Rewrite synced theme references so consumers use the canonical asset URLs. - Infer the shared layouts and includes each consuming site actually uses. - Infer obsolete shared asset paths at sync time instead of hardcoding them. - Rewrite shared image front matter to avoid broken local metadata URLs. - Avoid syncing feed references to sites without posts.
1 parent 702ab30 commit f424f17

2 files changed

Lines changed: 175 additions & 19 deletions

File tree

.github/actions/sync/shared-config.rb

Lines changed: 175 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
require "fileutils"
66
require "find"
77
require "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
812
require "yaml"
913

1014
# This makes sense for a standalone script.
@@ -43,14 +47,7 @@ def git(*args)
4347
stale_issues_workflow_yaml = ".github/workflows/stale-issues.yml"
4448
zizmor_yml = ".github/zizmor.yml"
4549
codeql_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

5552
homebrew_docs = homebrew_repository_path/docs
5653
homebrew_ruby_version =
@@ -282,28 +279,146 @@ def git(*args)
282279
end
283280
end
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
326485
end
327486

.github/workflows/sync-shared-config.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@ jobs:
121121
sparse-checkout: |
122122
_includes
123123
_layouts
124-
_sass
125-
assets/css
126-
assets/img
127124
bin
128125
129126
- name: Clone target repository

0 commit comments

Comments
 (0)