bridgetown-core 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +42 -0
  3. data/bridgetown-core.gemspec +46 -0
  4. data/lib/bridgetown-core.rb +202 -0
  5. data/lib/bridgetown-core/cache.rb +190 -0
  6. data/lib/bridgetown-core/cleaner.rb +111 -0
  7. data/lib/bridgetown-core/collection.rb +279 -0
  8. data/lib/bridgetown-core/command.rb +106 -0
  9. data/lib/bridgetown-core/commands/build.rb +96 -0
  10. data/lib/bridgetown-core/commands/clean.rb +43 -0
  11. data/lib/bridgetown-core/commands/console.rb +56 -0
  12. data/lib/bridgetown-core/commands/doctor.rb +172 -0
  13. data/lib/bridgetown-core/commands/help.rb +34 -0
  14. data/lib/bridgetown-core/commands/new.rb +148 -0
  15. data/lib/bridgetown-core/commands/serve.rb +273 -0
  16. data/lib/bridgetown-core/commands/serve/servlet.rb +68 -0
  17. data/lib/bridgetown-core/configuration.rb +323 -0
  18. data/lib/bridgetown-core/converter.rb +54 -0
  19. data/lib/bridgetown-core/converters/identity.rb +39 -0
  20. data/lib/bridgetown-core/converters/markdown.rb +108 -0
  21. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +132 -0
  22. data/lib/bridgetown-core/converters/smartypants.rb +69 -0
  23. data/lib/bridgetown-core/convertible.rb +237 -0
  24. data/lib/bridgetown-core/deprecator.rb +50 -0
  25. data/lib/bridgetown-core/document.rb +475 -0
  26. data/lib/bridgetown-core/drops/bridgetown_drop.rb +32 -0
  27. data/lib/bridgetown-core/drops/collection_drop.rb +20 -0
  28. data/lib/bridgetown-core/drops/document_drop.rb +69 -0
  29. data/lib/bridgetown-core/drops/drop.rb +215 -0
  30. data/lib/bridgetown-core/drops/excerpt_drop.rb +19 -0
  31. data/lib/bridgetown-core/drops/page_drop.rb +14 -0
  32. data/lib/bridgetown-core/drops/site_drop.rb +62 -0
  33. data/lib/bridgetown-core/drops/static_file_drop.rb +14 -0
  34. data/lib/bridgetown-core/drops/unified_payload_drop.rb +26 -0
  35. data/lib/bridgetown-core/drops/url_drop.rb +132 -0
  36. data/lib/bridgetown-core/entry_filter.rb +108 -0
  37. data/lib/bridgetown-core/errors.rb +20 -0
  38. data/lib/bridgetown-core/excerpt.rb +202 -0
  39. data/lib/bridgetown-core/external.rb +62 -0
  40. data/lib/bridgetown-core/filters.rb +467 -0
  41. data/lib/bridgetown-core/filters/date_filters.rb +110 -0
  42. data/lib/bridgetown-core/filters/grouping_filters.rb +64 -0
  43. data/lib/bridgetown-core/filters/url_filters.rb +79 -0
  44. data/lib/bridgetown-core/frontmatter_defaults.rb +238 -0
  45. data/lib/bridgetown-core/generator.rb +5 -0
  46. data/lib/bridgetown-core/hooks.rb +103 -0
  47. data/lib/bridgetown-core/layout.rb +57 -0
  48. data/lib/bridgetown-core/liquid_extensions.rb +22 -0
  49. data/lib/bridgetown-core/liquid_renderer.rb +71 -0
  50. data/lib/bridgetown-core/liquid_renderer/file.rb +67 -0
  51. data/lib/bridgetown-core/liquid_renderer/table.rb +75 -0
  52. data/lib/bridgetown-core/log_adapter.rb +151 -0
  53. data/lib/bridgetown-core/log_writer.rb +60 -0
  54. data/lib/bridgetown-core/mime.types +867 -0
  55. data/lib/bridgetown-core/page.rb +214 -0
  56. data/lib/bridgetown-core/page_without_a_file.rb +14 -0
  57. data/lib/bridgetown-core/path_manager.rb +31 -0
  58. data/lib/bridgetown-core/plugin.rb +80 -0
  59. data/lib/bridgetown-core/plugin_manager.rb +60 -0
  60. data/lib/bridgetown-core/publisher.rb +23 -0
  61. data/lib/bridgetown-core/reader.rb +185 -0
  62. data/lib/bridgetown-core/readers/collection_reader.rb +22 -0
  63. data/lib/bridgetown-core/readers/data_reader.rb +75 -0
  64. data/lib/bridgetown-core/readers/layout_reader.rb +48 -0
  65. data/lib/bridgetown-core/readers/page_reader.rb +24 -0
  66. data/lib/bridgetown-core/readers/post_reader.rb +74 -0
  67. data/lib/bridgetown-core/readers/static_file_reader.rb +24 -0
  68. data/lib/bridgetown-core/regenerator.rb +195 -0
  69. data/lib/bridgetown-core/related_posts.rb +52 -0
  70. data/lib/bridgetown-core/renderer.rb +261 -0
  71. data/lib/bridgetown-core/site.rb +469 -0
  72. data/lib/bridgetown-core/static_file.rb +205 -0
  73. data/lib/bridgetown-core/tags/component.rb +34 -0
  74. data/lib/bridgetown-core/tags/highlight.rb +111 -0
  75. data/lib/bridgetown-core/tags/include.rb +220 -0
  76. data/lib/bridgetown-core/tags/link.rb +41 -0
  77. data/lib/bridgetown-core/tags/post_url.rb +107 -0
  78. data/lib/bridgetown-core/url.rb +164 -0
  79. data/lib/bridgetown-core/utils.rb +367 -0
  80. data/lib/bridgetown-core/utils/ansi.rb +57 -0
  81. data/lib/bridgetown-core/utils/exec.rb +26 -0
  82. data/lib/bridgetown-core/utils/internet.rb +37 -0
  83. data/lib/bridgetown-core/utils/platforms.rb +80 -0
  84. data/lib/bridgetown-core/utils/thread_event.rb +31 -0
  85. data/lib/bridgetown-core/utils/win_tz.rb +75 -0
  86. data/lib/bridgetown-core/version.rb +5 -0
  87. data/lib/bridgetown-core/watcher.rb +139 -0
  88. data/lib/site_template/.gitignore +6 -0
  89. data/lib/site_template/bridgetown.config.yml +21 -0
  90. data/lib/site_template/frontend/javascript/index.js +3 -0
  91. data/lib/site_template/frontend/styles/index.scss +17 -0
  92. data/lib/site_template/package.json +23 -0
  93. data/lib/site_template/src/404.html +9 -0
  94. data/lib/site_template/src/_data/site_metadata.yml +11 -0
  95. data/lib/site_template/src/_includes/footer.html +3 -0
  96. data/lib/site_template/src/_includes/head.html +9 -0
  97. data/lib/site_template/src/_includes/navbar.html +4 -0
  98. data/lib/site_template/src/_layouts/default.html +15 -0
  99. data/lib/site_template/src/_layouts/home.html +7 -0
  100. data/lib/site_template/src/_layouts/page.html +7 -0
  101. data/lib/site_template/src/_layouts/post.html +7 -0
  102. data/lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb +26 -0
  103. data/lib/site_template/src/about.md +11 -0
  104. data/lib/site_template/src/index.md +7 -0
  105. data/lib/site_template/webpack.config.js +60 -0
  106. data/rake/release.rake +30 -0
  107. metadata +106 -1
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ # Handles the cleanup of a site's destination before it is built.
5
+ class Cleaner
6
+ HIDDEN_FILE_REGEX = %r!\/\.{1,2}$!.freeze
7
+ attr_reader :site
8
+
9
+ def initialize(site)
10
+ @site = site
11
+ end
12
+
13
+ # Cleans up the site's destination directory
14
+ def cleanup!
15
+ FileUtils.rm_rf(obsolete_files)
16
+ FileUtils.rm_rf(metadata_file) unless @site.incremental?
17
+ end
18
+
19
+ private
20
+
21
+ # Private: The list of files and directories to be deleted during cleanup process
22
+ #
23
+ # Returns an Array of the file and directory paths
24
+ def obsolete_files
25
+ out = (existing_files - new_files - new_dirs + replaced_files).to_a
26
+ Bridgetown::Hooks.trigger :clean, :on_obsolete, out
27
+ out
28
+ end
29
+
30
+ # Private: The metadata file storing dependency tree and build history
31
+ #
32
+ # Returns an Array with the metdata file as the only item
33
+ def metadata_file
34
+ [site.regenerator.metadata_file]
35
+ end
36
+
37
+ # Private: The list of existing files, apart from those included in
38
+ # keep_files and hidden files.
39
+ #
40
+ # Returns a Set with the file paths
41
+ def existing_files
42
+ files = Set.new
43
+ regex = keep_file_regex
44
+ dirs = keep_dirs
45
+
46
+ Utils.safe_glob(site.in_dest_dir, ["**", "*"], File::FNM_DOTMATCH).each do |file|
47
+ next if file =~ HIDDEN_FILE_REGEX || file =~ regex || dirs.include?(file)
48
+
49
+ files << file
50
+ end
51
+
52
+ files
53
+ end
54
+
55
+ # Private: The list of files to be created when site is built.
56
+ #
57
+ # Returns a Set with the file paths
58
+ def new_files
59
+ @new_files ||= Set.new.tap do |files|
60
+ site.each_site_file { |item| files << item.destination(site.dest) }
61
+ end
62
+ end
63
+
64
+ # Private: The list of directories to be created when site is built.
65
+ # These are the parent directories of the files in #new_files.
66
+ #
67
+ # Returns a Set with the directory paths
68
+ def new_dirs
69
+ @new_dirs ||= new_files.flat_map { |file| parent_dirs(file) }.to_set
70
+ end
71
+
72
+ # Private: The list of parent directories of a given file
73
+ #
74
+ # Returns an Array with the directory paths
75
+ def parent_dirs(file)
76
+ parent_dir = File.dirname(file)
77
+ if parent_dir == site.dest
78
+ []
79
+ else
80
+ parent_dirs(parent_dir).unshift(parent_dir)
81
+ end
82
+ end
83
+
84
+ # Private: The list of existing files that will be replaced by a directory
85
+ # during build
86
+ #
87
+ # Returns a Set with the file paths
88
+ def replaced_files
89
+ new_dirs.select { |dir| File.file?(dir) }.to_set
90
+ end
91
+
92
+ # Private: The list of directories that need to be kept because they are
93
+ # parent directories of files specified in keep_files
94
+ #
95
+ # Returns a Set with the directory paths
96
+ def keep_dirs
97
+ site.keep_files.flat_map { |file| parent_dirs(site.in_dest_dir(file)) }.to_set
98
+ end
99
+
100
+ # Private: Creates a regular expression from the config's keep_files array
101
+ #
102
+ # Examples
103
+ # ['.git','.svn'] with site.dest "/myblog/_site" creates
104
+ # the following regex: /\A\/myblog\/_site\/(\.git|\/.svn)/
105
+ #
106
+ # Returns the regular expression
107
+ def keep_file_regex
108
+ %r!\A#{Regexp.quote(site.dest)}\/(#{Regexp.union(site.keep_files).source})!
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,279 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ class Collection
5
+ attr_reader :site, :label, :metadata
6
+ attr_writer :docs
7
+
8
+ # Create a new Collection.
9
+ #
10
+ # site - the site to which this collection belongs.
11
+ # label - the name of the collection
12
+ #
13
+ # Returns nothing.
14
+ def initialize(site, label)
15
+ @site = site
16
+ @label = sanitize_label(label)
17
+ @metadata = extract_metadata
18
+ end
19
+
20
+ # Fetch the Documents in this collection.
21
+ # Defaults to an empty array if no documents have been read in.
22
+ #
23
+ # Returns an array of Bridgetown::Document objects.
24
+ def docs
25
+ @docs ||= []
26
+ end
27
+
28
+ # Override of normal respond_to? to match method_missing's logic for
29
+ # looking in @data.
30
+ def respond_to_missing?(method, include_private = false)
31
+ docs.respond_to?(method.to_sym, include_private) || super
32
+ end
33
+
34
+ # Override of method_missing to check in @data for the key.
35
+ def method_missing(method, *args, &blck)
36
+ if docs.respond_to?(method.to_sym)
37
+ Bridgetown.logger.warn "Deprecation:",
38
+ "#{label}.#{method} should be changed to #{label}.docs.#{method}."
39
+ Bridgetown.logger.warn "", "Called by #{caller(0..0)}."
40
+ docs.public_send(method.to_sym, *args, &blck)
41
+ else
42
+ super
43
+ end
44
+ end
45
+
46
+ # Fetch the static files in this collection.
47
+ # Defaults to an empty array if no static files have been read in.
48
+ #
49
+ # Returns an array of Bridgetown::StaticFile objects.
50
+ def files
51
+ @files ||= []
52
+ end
53
+
54
+ # Read the allowed documents into the collection's array of docs.
55
+ #
56
+ # Returns the sorted array of docs.
57
+ def read
58
+ filtered_entries.each do |file_path|
59
+ full_path = collection_dir(file_path)
60
+ next if File.directory?(full_path)
61
+
62
+ if Utils.has_yaml_header? full_path
63
+ read_document(full_path)
64
+ else
65
+ read_static_file(file_path, full_path)
66
+ end
67
+ end
68
+ sort_docs!
69
+ end
70
+
71
+ # All the entries in this collection.
72
+ #
73
+ # Returns an Array of file paths to the documents in this collection
74
+ # relative to the collection's directory
75
+ def entries
76
+ return [] unless exists?
77
+
78
+ @entries ||= begin
79
+ collection_dir_slash = "#{collection_dir}/"
80
+ Utils.safe_glob(collection_dir, ["**", "*"], File::FNM_DOTMATCH).map do |entry|
81
+ entry[collection_dir_slash] = ""
82
+ entry
83
+ end
84
+ end
85
+ end
86
+
87
+ # Filtered version of the entries in this collection.
88
+ # See `Bridgetown::EntryFilter#filter` for more information.
89
+ #
90
+ # Returns a list of filtered entry paths.
91
+ def filtered_entries
92
+ return [] unless exists?
93
+
94
+ @filtered_entries ||=
95
+ Dir.chdir(directory) do
96
+ entry_filter.filter(entries).reject do |f|
97
+ path = collection_dir(f)
98
+ File.directory?(path) || entry_filter.symlink?(f)
99
+ end
100
+ end
101
+ end
102
+
103
+ # The directory for this Collection, relative to the site source or the directory
104
+ # containing the collection.
105
+ #
106
+ # Returns a String containing the directory name where the collection
107
+ # is stored on the filesystem.
108
+ def relative_directory
109
+ @relative_directory ||= "_#{label}"
110
+ end
111
+
112
+ # The full path to the directory containing the collection.
113
+ #
114
+ # Returns a String containing th directory name where the collection
115
+ # is stored on the filesystem.
116
+ def directory
117
+ @directory ||= site.in_source_dir(
118
+ File.join(container, relative_directory)
119
+ )
120
+ end
121
+
122
+ # The full path to the directory containing the collection, with
123
+ # optional subpaths.
124
+ #
125
+ # *files - (optional) any other path pieces relative to the
126
+ # directory to append to the path
127
+ #
128
+ # Returns a String containing th directory name where the collection
129
+ # is stored on the filesystem.
130
+ def collection_dir(*files)
131
+ return directory if files.empty?
132
+
133
+ site.in_source_dir(container, relative_directory, *files)
134
+ end
135
+
136
+ # Checks whether the directory "exists" for this collection.
137
+ def exists?
138
+ File.directory?(directory)
139
+ end
140
+
141
+ # The entry filter for this collection.
142
+ # Creates an instance of Bridgetown::EntryFilter.
143
+ #
144
+ # Returns the instance of Bridgetown::EntryFilter for this collection.
145
+ def entry_filter
146
+ @entry_filter ||= Bridgetown::EntryFilter.new(site, relative_directory)
147
+ end
148
+
149
+ # An inspect string.
150
+ #
151
+ # Returns the inspect string
152
+ def inspect
153
+ "#<#{self.class} @label=#{label} docs=#{docs}>"
154
+ end
155
+
156
+ # Produce a sanitized label name
157
+ # Label names may not contain anything but alphanumeric characters,
158
+ # underscores, and hyphens.
159
+ #
160
+ # label - the possibly-unsafe label
161
+ #
162
+ # Returns a sanitized version of the label.
163
+ def sanitize_label(label)
164
+ label.gsub(%r![^a-z0-9_\-\.]!i, "")
165
+ end
166
+
167
+ # Produce a representation of this Collection for use in Liquid.
168
+ # Exposes two attributes:
169
+ # - label
170
+ # - docs
171
+ #
172
+ # Returns a representation of this collection for use in Liquid.
173
+ def to_liquid
174
+ Drops::CollectionDrop.new self
175
+ end
176
+
177
+ # Whether the collection's documents ought to be written as individual
178
+ # files in the output.
179
+ #
180
+ # Returns true if the 'write' metadata is true, false otherwise.
181
+ def write?
182
+ !!metadata.fetch("output", false)
183
+ end
184
+
185
+ # The URL template to render collection's documents at.
186
+ #
187
+ # Returns the URL template to render collection's documents at.
188
+ def url_template
189
+ @url_template ||= metadata.fetch("permalink") do
190
+ Utils.add_permalink_suffix("/:collection/:path", site.permalink_style)
191
+ end
192
+ end
193
+
194
+ # Extract options for this collection from the site configuration.
195
+ #
196
+ # Returns the metadata for this collection
197
+ def extract_metadata
198
+ if site.config["collections"].is_a?(Hash)
199
+ site.config["collections"][label] || {}
200
+ else
201
+ {}
202
+ end
203
+ end
204
+
205
+ private
206
+
207
+ def container
208
+ @container ||= site.config["collections_dir"]
209
+ end
210
+
211
+ def read_document(full_path)
212
+ doc = Document.new(full_path, :site => site, :collection => self)
213
+ doc.read
214
+ docs << doc if site.unpublished || doc.published?
215
+ end
216
+
217
+ def sort_docs!
218
+ if metadata["sort_by"].is_a?(String)
219
+ sort_docs_by_key!
220
+ else
221
+ docs.sort!
222
+ end
223
+ end
224
+
225
+ # A custom sort function based on Schwartzian transform
226
+ # Refer https://byparker.com/blog/2017/schwartzian-transform-faster-sorting/ for details
227
+ def sort_docs_by_key!
228
+ meta_key = metadata["sort_by"]
229
+ # Modify `docs` array to cache document's property along with the Document instance
230
+ docs.map! { |doc| [doc.data[meta_key], doc] }.sort! do |apples, olives|
231
+ order = determine_sort_order(meta_key, apples, olives)
232
+
233
+ # Fall back to `Document#<=>` if the properties were equal or were non-sortable
234
+ # Otherwise continue with current sort-order
235
+ if order.nil? || order.zero?
236
+ apples[-1] <=> olives[-1]
237
+ else
238
+ order
239
+ end
240
+
241
+ # Finally restore the `docs` array with just the Document objects themselves
242
+ end.map!(&:last)
243
+ end
244
+
245
+ def determine_sort_order(sort_key, apples, olives)
246
+ apple_property, apple_document = apples
247
+ olive_property, olive_document = olives
248
+
249
+ if apple_property.nil? && !olive_property.nil?
250
+ order_with_warning(sort_key, apple_document, 1)
251
+ elsif !apple_property.nil? && olive_property.nil?
252
+ order_with_warning(sort_key, olive_document, -1)
253
+ else
254
+ apple_property <=> olive_property
255
+ end
256
+ end
257
+
258
+ def order_with_warning(sort_key, document, order)
259
+ Bridgetown.logger.warn "Sort warning:", "'#{sort_key}' not defined in" \
260
+ " #{document.relative_path}"
261
+ order
262
+ end
263
+
264
+ def read_static_file(file_path, full_path)
265
+ relative_dir = Bridgetown.sanitized_path(
266
+ relative_directory,
267
+ File.dirname(file_path)
268
+ ).chomp("/.")
269
+
270
+ files << StaticFile.new(
271
+ site,
272
+ site.source,
273
+ relative_dir,
274
+ File.basename(full_path),
275
+ self
276
+ )
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ class Command
5
+ class << self
6
+ # A list of subclasses of Bridgetown::Command
7
+ def subclasses
8
+ @subclasses ||= []
9
+ end
10
+
11
+ # Keep a list of subclasses of Bridgetown::Command every time it's inherited
12
+ # Called automatically.
13
+ #
14
+ # base - the subclass
15
+ #
16
+ # Returns nothing
17
+ def inherited(base)
18
+ subclasses << base
19
+ super(base)
20
+ end
21
+
22
+ # Run Site#process and catch errors
23
+ #
24
+ # site - the Bridgetown::Site object
25
+ #
26
+ # Returns nothing
27
+ def process_site(site)
28
+ site.process
29
+ rescue Bridgetown::Errors::FatalException => e
30
+ Bridgetown.logger.error "ERROR:", "YOUR SITE COULD NOT BE BUILT:"
31
+ Bridgetown.logger.error "", "------------------------------------"
32
+ Bridgetown.logger.error "", e.message
33
+ exit(1)
34
+ end
35
+
36
+ # Create a full Bridgetown configuration with the options passed in as overrides
37
+ #
38
+ # options - the configuration overrides
39
+ #
40
+ # Returns a full Bridgetown configuration
41
+ def configuration_from_options(options)
42
+ return options if options.is_a?(Bridgetown::Configuration)
43
+
44
+ Bridgetown.configuration(options)
45
+ end
46
+
47
+ # Add common options to a command for building configuration
48
+ #
49
+ # cmd - the Bridgetown::Command to add these options to
50
+ #
51
+ # Returns nothing
52
+ # rubocop:disable Metrics/MethodLength
53
+ def add_build_options(cmd)
54
+ cmd.option "config", "--config CONFIG_FILE[,CONFIG_FILE2,...]",
55
+ Array, "Custom configuration file"
56
+ cmd.option "destination", "-d", "--destination DESTINATION",
57
+ "The current folder will be generated into DESTINATION"
58
+ cmd.option "root_dir", "-r", "--root_dir ROOT_DIR", "The top-level root folder" \
59
+ " where config files are located"
60
+ cmd.option "source", "-s", "--source SOURCE", "Custom source directory"
61
+ cmd.option "future", "--future", "Publishes posts with a future date"
62
+ cmd.option "limit_posts", "--limit_posts MAX_POSTS", Integer,
63
+ "Limits the number of posts to parse and publish"
64
+ cmd.option "watch", "-w", "--[no-]watch", "Watch for changes and rebuild"
65
+ cmd.option "baseurl", "-b", "--baseurl URL",
66
+ "Serve the website from the given base URL"
67
+ cmd.option "force_polling", "--force_polling", "Force watch to use polling"
68
+ cmd.option "lsi", "--lsi", "Use LSI for improved related posts"
69
+ cmd.option "unpublished", "--unpublished",
70
+ "Render posts that were marked as unpublished"
71
+ cmd.option "disable_disk_cache", "--disable-disk-cache",
72
+ "Disable caching to disk"
73
+ cmd.option "quiet", "-q", "--quiet", "Silence output."
74
+ cmd.option "verbose", "-V", "--verbose", "Print verbose output."
75
+ cmd.option "incremental", "-I", "--incremental", "Enable incremental rebuild."
76
+ cmd.option "strict_front_matter", "--strict_front_matter",
77
+ "Fail if errors are present in front matter"
78
+ end
79
+ # rubocop:enable Metrics/MethodLength
80
+
81
+ # Run ::process method in a given set of Bridgetown::Command subclasses and suggest
82
+ # re-running the associated command with --trace switch to obtain any additional
83
+ # information or backtrace regarding the encountered Exception.
84
+ #
85
+ # cmd - the Bridgetown::Command to be handled
86
+ # options - configuration overrides
87
+ # klass - an array of Bridgetown::Command subclasses associated with the command
88
+ #
89
+ # Note that all exceptions are rescued..
90
+ # rubocop: disable Lint/RescueException
91
+ def process_with_graceful_fail(cmd, options, *klass)
92
+ klass.each { |k| k.process(options) if k.respond_to?(:process) }
93
+ rescue Exception => e
94
+ raise e if cmd.trace
95
+
96
+ msg = " Please append `--trace` to the `#{cmd.name}` command "
97
+ dashes = "-" * msg.length
98
+ Bridgetown.logger.error "", dashes
99
+ Bridgetown.logger.error "Bridgetown #{Bridgetown::VERSION} ", msg
100
+ Bridgetown.logger.error "", " for any additional information or backtrace. "
101
+ Bridgetown.logger.abort_with "", dashes
102
+ end
103
+ # rubocop: enable Lint/RescueException
104
+ end
105
+ end
106
+ end