diff --git a/bridgetown-core/lib/bridgetown-core/collection.rb b/bridgetown-core/lib/bridgetown-core/collection.rb index 1132a6bf8..e0f5a1526 100644 --- a/bridgetown-core/lib/bridgetown-core/collection.rb +++ b/bridgetown-core/lib/bridgetown-core/collection.rb @@ -368,9 +368,12 @@ def read_static_file(file_path, full_path) end def relative_model_path_for(full_path, manifest: nil) - Pathname(full_path).relative_path_from( - manifest ? Pathname(manifest.content) : Pathname(site.source) - ).to_s + content_root = if manifest + manifest.contents ? manifest.contents[label.to_sym] : manifest.content + else + site.source + end + Pathname(full_path).relative_path_from(content_root).to_s end def model_id_from_relative_path(model_relative_path, manifest: nil) diff --git a/bridgetown-core/lib/bridgetown-core/commands/plugins.rb b/bridgetown-core/lib/bridgetown-core/commands/plugins.rb index 0e499aa8d..80d4a8831 100644 --- a/bridgetown-core/lib/bridgetown-core/commands/plugins.rb +++ b/bridgetown-core/lib/bridgetown-core/commands/plugins.rb @@ -61,7 +61,9 @@ def list site.config.source_manifests.each do |manifest| Bridgetown.logger.info("Origin:", (manifest.origin || "n/a").to_s.green) Bridgetown.logger.info("Components:", (manifest.components || "n/a").to_s.cyan) - Bridgetown.logger.info("Content:", (manifest.content || "n/a").to_s.cyan) + Bridgetown.logger.info("Contents:", ( + manifest.contents&.map { |k, v| "#{v} (#{k})" }&.join(", ") || manifest.content || "n/a" + ).to_s.cyan) Bridgetown.logger.info("Layouts:", (manifest.layouts || "n/a").to_s.cyan) Bridgetown.logger.info("", "----") diff --git a/bridgetown-core/lib/bridgetown-core/configuration.rb b/bridgetown-core/lib/bridgetown-core/configuration.rb index c50cdbe7d..e2178bb40 100644 --- a/bridgetown-core/lib/bridgetown-core/configuration.rb +++ b/bridgetown-core/lib/bridgetown-core/configuration.rb @@ -3,7 +3,8 @@ module Bridgetown # The primary configuration object for a Bridgetown project class Configuration < HashWithDotAccess::Hash - REQUIRE_DENYLIST = %i(parse_routes ssr) # rubocop:disable Style/MutableConstant + # Built-in initializer list which isn't Gem-backed: + REQUIRE_DENYLIST = %i(external_sources parse_routes ssr) # rubocop:disable Style/MutableConstant Initializer = Struct.new(:name, :block, :completed, keyword_init: true) do def to_s @@ -11,7 +12,9 @@ def to_s end end - SourceManifest = Struct.new(:origin, :components, :content, :layouts, keyword_init: true) + SourceManifest = Struct.new( + :origin, :components, :content, :contents, :layouts, keyword_init: true + ) Preflight = Struct.new(:source_manifests, :initializers, keyword_init: true) do def initialize(*) diff --git a/bridgetown-core/lib/bridgetown-core/front_matter/defaults.rb b/bridgetown-core/lib/bridgetown-core/front_matter/defaults.rb index d9041ba99..9b8281ace 100644 --- a/bridgetown-core/lib/bridgetown-core/front_matter/defaults.rb +++ b/bridgetown-core/lib/bridgetown-core/front_matter/defaults.rb @@ -16,6 +16,7 @@ def initialize(site) def reset @glob_cache = {} @defaults_cache = {} + @sets = nil end def ensure_time!(set) @@ -185,10 +186,10 @@ def matching_sets(path, collection) # # @return [Array] def valid_sets - sets = site.config["defaults"] - return [] unless sets.is_a?(Array) + @sets ||= site.config["defaults"].map { HashWithDotAccess::Hash.new(_1) } + return [] unless @sets.is_a?(Array) - sets.filter_map do |set| + @sets.filter_map do |set| if valid?(set) massage_scope!(set) # TODO: is this trip really necessary? diff --git a/bridgetown-core/lib/bridgetown-core/model/plugin_origin.rb b/bridgetown-core/lib/bridgetown-core/model/plugin_origin.rb index aef2a6681..5e8b13c7a 100644 --- a/bridgetown-core/lib/bridgetown-core/model/plugin_origin.rb +++ b/bridgetown-core/lib/bridgetown-core/model/plugin_origin.rb @@ -27,7 +27,9 @@ def relative_path end def original_path - @original_path ||= relative_path.expand_path(manifest.content) + @original_path ||= relative_path.expand_path( + manifest.dig(:contents, collection.label.to_sym) || manifest.content + ) end end end diff --git a/bridgetown-core/lib/bridgetown-core/reader.rb b/bridgetown-core/lib/bridgetown-core/reader.rb index 639a07a3a..1131b9214 100644 --- a/bridgetown-core/lib/bridgetown-core/reader.rb +++ b/bridgetown-core/lib/bridgetown-core/reader.rb @@ -20,7 +20,7 @@ def read read_includes sort_files! read_collections - site.config.source_manifests.select(&:content).each do |manifest| + site.config.source_manifests.each do |manifest| PluginContentReader.new(site, manifest).read end end @@ -66,7 +66,7 @@ def read_directories(dir = "") entries = Dir.chdir(base) { filter_entries(Dir.entries("."), base) } entries.each do |entry| - file_path = @site.in_source_dir(base, entry) + file_path = site.in_source_dir(base, entry) if File.directory?(file_path) entries_dirs << entry elsif FrontMatter::Loaders.front_matter?(file_path) diff --git a/bridgetown-core/lib/bridgetown-core/readers/plugin_content_reader.rb b/bridgetown-core/lib/bridgetown-core/readers/plugin_content_reader.rb index 9161be68f..0cec4db36 100644 --- a/bridgetown-core/lib/bridgetown-core/readers/plugin_content_reader.rb +++ b/bridgetown-core/lib/bridgetown-core/readers/plugin_content_reader.rb @@ -2,19 +2,38 @@ module Bridgetown class PluginContentReader - attr_reader :site, :manifest, :content_dir + attr_reader :site, :manifest, :content_dirs # @param site [Bridgetown::Site] # @param manifest [Bridgetown::Plugin::SourceManifest] def initialize(site, manifest) @site = site @manifest = manifest - @content_dir = manifest.content + @content_dirs = if manifest.contents + manifest.contents + elsif manifest.content + { pages: manifest.content } + end @content_files = Set.new end def read - return unless content_dir + return if content_dirs.empty? + + content_dirs.each do |collection_name, root| + read_content_root collection_name, root + end + end + + def read_content_root(collection_name, content_dir) + collection = site.collections[collection_name] + unless collection + Bridgetown.logger.warn( + "Reading", + "Plugin requested missing collection #{collection_name}, cannot continue" + ) + return + end Find.find(content_dir) do |path| next if File.directory?(path) @@ -22,17 +41,17 @@ def read if File.symlink?(path) Bridgetown.logger.warn "Plugin content reader:", "Ignored symlinked asset: #{path}" else - read_content_file(path) + read_content_file(content_dir, path, collection) end end end - def read_content_file(path) + def read_content_file(content_dir, path, collection) dir = File.dirname(path.sub("#{content_dir}/", "")) name = File.basename(path) @content_files << if FrontMatter::Loaders.front_matter?(path) - site.collections.pages.read_resource(path, manifest:) + collection.read_resource(path, manifest:) else Bridgetown::StaticFile.new(site, content_dir, "/#{dir}", name) end diff --git a/bridgetown-core/lib/bridgetown-core/utils/initializers.rb b/bridgetown-core/lib/bridgetown-core/utils/initializers.rb index 51efea836..84abb4481 100644 --- a/bridgetown-core/lib/bridgetown-core/utils/initializers.rb +++ b/bridgetown-core/lib/bridgetown-core/utils/initializers.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +# Make sure you update REQUIRE_DENYLIST in `Bridgetown::Configuration` for initializers which +# aren't Gem backed + Bridgetown.initializer :dotenv do |config| Bridgetown.load_dotenv root: config.root_dir end @@ -10,6 +13,15 @@ end end +Bridgetown.initializer :external_sources do |config, contents:| + Bridgetown::ExternalSources = Module.new + + config.source_manifest( + origin: Bridgetown::ExternalSources, + contents: + ) +end + Bridgetown.initializer :parse_routes do |config| # This builds upon the work done here: # https://github.com/jeremyevans/roda-route_list/blob/master/bin/roda-parse_routes