Class: Stylesheet::Manager::Builder
- Inherits:
-
Object
- Object
- Stylesheet::Manager::Builder
- Defined in:
- lib/stylesheet/manager/builder.rb
Instance Attribute Summary collapse
-
#theme ⇒ Object
readonly
Returns the value of attribute theme.
Instance Method Summary collapse
- #cache_fullpath ⇒ Object
- #color_scheme_digest ⇒ Object
- #compile(opts = {}) ⇒ Object
- #current_hostname ⇒ Object
- #default_digest ⇒ Object
-
#digest ⇒ Object
digest encodes the things that trigger a recompile.
-
#initialize(target: :desktop, theme: nil, color_scheme: nil, manager:) ⇒ Builder
constructor
A new instance of Builder.
- #is_color_scheme? ⇒ Boolean
- #is_theme? ⇒ Boolean
-
#plugins_digest ⇒ Object
this protects us from situations where new versions of a plugin removed a file old instances may still be serving CSS and not aware of the change so we could end up poisoning the cache with a bad file that can not be removed.
- #qualified_target ⇒ Object
- #resolve_baked_field(target, name) ⇒ Object
- #root_path ⇒ Object
- #scheme_slug ⇒ Object
- #scss_digest ⇒ Object
- #settings_digest ⇒ Object
- #source_map_filename ⇒ Object
- #source_map_fullpath ⇒ Object
- #source_map_url_relative_from_stylesheet ⇒ Object
- #stylesheet_absolute_url ⇒ Object
- #stylesheet_filename(with_digest = true) ⇒ Object
- #stylesheet_filename_no_digest ⇒ Object
- #stylesheet_fullpath ⇒ Object
- #stylesheet_fullpath_no_digest ⇒ Object
- #stylesheet_relpath ⇒ Object
- #stylesheet_relpath_no_digest ⇒ Object
- #theme_digest ⇒ Object
- #uploads_digest ⇒ Object
- #with_load_paths ⇒ Object
Constructor Details
#initialize(target: :desktop, theme: nil, color_scheme: nil, manager:) ⇒ Builder
Returns a new instance of Builder.
6 7 8 9 10 11 |
# File 'lib/stylesheet/manager/builder.rb', line 6 def initialize(target: :desktop, theme: nil, color_scheme: nil, manager:) @target = target @theme = theme @color_scheme = color_scheme @manager = manager end |
Instance Attribute Details
#theme ⇒ Object (readonly)
Returns the value of attribute theme.
4 5 6 |
# File 'lib/stylesheet/manager/builder.rb', line 4 def theme @theme end |
Instance Method Details
#cache_fullpath ⇒ Object
81 82 83 |
# File 'lib/stylesheet/manager/builder.rb', line 81 def cache_fullpath Stylesheet::Manager.cache_fullpath end |
#color_scheme_digest ⇒ Object
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/stylesheet/manager/builder.rb', line 240 def color_scheme_digest cs = @color_scheme || theme&.color_scheme fonts = "#{SiteSetting.base_font}-#{SiteSetting.heading_font}" digest_string = "#{current_hostname}-" if cs theme_color_defs = resolve_baked_field(:common, :color_definitions) digest_string += "#{RailsMultisite::ConnectionManagement.current_db}-#{cs&.id}-#{cs&.version}-#{theme_color_defs}-#{Stylesheet::Manager.fs_asset_cachebuster}-#{fonts}" else digest_string += "defaults-#{Stylesheet::Manager.fs_asset_cachebuster}-#{fonts}" if cdn_url = GlobalSetting.cdn_url digest_string += "-#{cdn_url}" end end Digest::SHA1.hexdigest digest_string end |
#compile(opts = {}) ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/stylesheet/manager/builder.rb', line 13 def compile(opts = {}) if !opts[:force] if File.exist?(stylesheet_fullpath) if !StylesheetCache.where(target: qualified_target, digest: digest).exists? begin source_map = begin File.read(source_map_fullpath) rescue Errno::ENOENT end StylesheetCache.add( qualified_target, digest, File.read(stylesheet_fullpath), source_map, ) rescue => e Rails.logger.warn "Completely unexpected error adding contents of '#{stylesheet_fullpath}' to cache #{e}" end end return true end end rtl = @target.to_s.end_with?("_rtl") css, source_map = with_load_paths do |load_paths| Stylesheet::Compiler.compile_asset( @target.to_s.gsub(/_rtl\z/, "").to_sym, rtl: rtl, theme_id: theme&.id, theme_variables: theme&.scss_variables.to_s, source_map_file: source_map_url_relative_from_stylesheet, color_scheme_id: @color_scheme&.id, load_paths: load_paths, ) rescue SassC::SyntaxError, SassC::NotRenderedError => e if Stylesheet::Importer::THEME_TARGETS.include?(@target.to_s) # no special errors for theme, handled in theme editor ["", nil] elsif @target.to_s == Stylesheet::Manager::COLOR_SCHEME_STYLESHEET # log error but do not crash for errors in color definitions SCSS Rails.logger.error "SCSS compilation error: #{e.}" ["", nil] else raise Discourse::ScssError, e. end end FileUtils.mkdir_p(cache_fullpath) File.open(stylesheet_fullpath, "w") { |f| f.puts css } File.open(source_map_fullpath, "w") { |f| f.puts source_map } if source_map.present? begin StylesheetCache.add(qualified_target, digest, css, source_map) rescue => e Rails.logger.warn "Completely unexpected error adding item to cache #{e}" end css end |
#current_hostname ⇒ Object
77 78 79 |
# File 'lib/stylesheet/manager/builder.rb', line 77 def current_hostname Discourse.current_hostname end |
#default_digest ⇒ Object
236 237 238 |
# File 'lib/stylesheet/manager/builder.rb', line 236 def default_digest Digest::SHA1.hexdigest "default-#{Stylesheet::Manager.fs_asset_cachebuster}-#{plugins_digest}-#{current_hostname}" end |
#digest ⇒ Object
digest encodes the things that trigger a recompile
154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/stylesheet/manager/builder.rb', line 154 def digest @digest ||= begin if is_theme? theme_digest elsif is_color_scheme? color_scheme_digest else default_digest end end end |
#is_color_scheme? ⇒ Boolean
145 146 147 |
# File 'lib/stylesheet/manager/builder.rb', line 145 def is_color_scheme? !!(@target.to_s == Stylesheet::Manager::COLOR_SCHEME_STYLESHEET) end |
#is_theme? ⇒ Boolean
141 142 143 |
# File 'lib/stylesheet/manager/builder.rb', line 141 def is_theme? !!(@target.to_s =~ Stylesheet::Manager::THEME_REGEX) end |
#plugins_digest ⇒ Object
this protects us from situations where new versions of a plugin removed a file old instances may still be serving CSS and not aware of the change so we could end up poisoning the cache with a bad file that can not be removed
195 196 197 198 199 200 201 |
# File 'lib/stylesheet/manager/builder.rb', line 195 def plugins_digest assets = [] DiscoursePluginRegistry.stylesheets.each { |_, paths| assets += paths.to_a } DiscoursePluginRegistry.mobile_stylesheets.each { |_, paths| assets += paths.to_a } DiscoursePluginRegistry.desktop_stylesheets.each { |_, paths| assets += paths.to_a } Digest::SHA1.hexdigest(assets.sort.join) end |
#qualified_target ⇒ Object
121 122 123 124 125 126 127 128 129 130 |
# File 'lib/stylesheet/manager/builder.rb', line 121 def qualified_target if is_theme? "#{@target}_#{theme&.id}" elsif @color_scheme "#{@target}_#{scheme_slug}_#{@color_scheme&.id}_#{@theme&.id}" else scheme_string = theme&.color_scheme ? "_#{theme.color_scheme.id}" : "" "#{@target}#{scheme_string}" end end |
#resolve_baked_field(target, name) ⇒ Object
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/stylesheet/manager/builder.rb', line 260 def resolve_baked_field(target, name) theme_ids = if !theme [] elsif Theme.is_parent_theme?(theme.id) @manager.theme_ids else [theme.id] end theme_ids = [theme_ids.first] if name != :color_definitions baked_fields = [] targets = [Theme.targets[target.to_sym], Theme.targets[:common]] @manager .load_themes(theme_ids) .each do |theme| theme.builder_theme_fields.each do |theme_field| if theme_field.name == name.to_s && targets.include?(theme_field.target_id) baked_fields << theme_field end end end baked_fields .map do |f| f.ensure_baked! f.value_baked || f.value end .join("\n") end |
#root_path ⇒ Object
109 110 111 |
# File 'lib/stylesheet/manager/builder.rb', line 109 def root_path "#{GlobalSetting.relative_url_root}/" end |
#scheme_slug ⇒ Object
149 150 151 |
# File 'lib/stylesheet/manager/builder.rb', line 149 def scheme_slug Slug.for(ActiveSupport::Inflector.transliterate(@color_scheme.name), "scheme") end |
#scss_digest ⇒ Object
175 176 177 178 179 180 181 182 183 |
# File 'lib/stylesheet/manager/builder.rb', line 175 def scss_digest if %i[mobile_theme desktop_theme].include?(@target) resolve_baked_field(@target.to_s.sub("_theme", ""), :scss) elsif @target == :embedded_theme resolve_baked_field(:common, :embedded_scss) else raise "attempting to look up theme digest for invalid field" end end |
#settings_digest ⇒ Object
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/stylesheet/manager/builder.rb', line 203 def settings_digest themes = if !theme [] elsif Theme.is_parent_theme?(theme.id) @manager.load_themes(@manager.theme_ids) else [@manager.get_theme(theme.id)] end fields = themes.each_with_object([]) do |theme, array| array.concat(theme.yaml_theme_fields.map(&:updated_at)) end settings = themes.each_with_object([]) do |theme, array| array.concat(theme.theme_settings.map(&:updated_at)) end = fields.concat(settings).map!(&:to_f).sort!.join(",") Digest::SHA1.hexdigest() end |
#source_map_filename ⇒ Object
93 94 95 |
# File 'lib/stylesheet/manager/builder.rb', line 93 def source_map_filename "#{stylesheet_filename}.map" end |
#source_map_fullpath ⇒ Object
89 90 91 |
# File 'lib/stylesheet/manager/builder.rb', line 89 def source_map_fullpath "#{cache_fullpath}/#{source_map_filename}" end |
#source_map_url_relative_from_stylesheet ⇒ Object
97 98 99 |
# File 'lib/stylesheet/manager/builder.rb', line 97 def source_map_url_relative_from_stylesheet "#{source_map_filename}?__ws=#{current_hostname}" end |
#stylesheet_absolute_url ⇒ Object
105 106 107 |
# File 'lib/stylesheet/manager/builder.rb', line 105 def stylesheet_absolute_url "#{GlobalSetting.cdn_url}#{stylesheet_relpath}?__ws=#{current_hostname}" end |
#stylesheet_filename(with_digest = true) ⇒ Object
132 133 134 135 |
# File 'lib/stylesheet/manager/builder.rb', line 132 def stylesheet_filename(with_digest = true) digest_string = "_#{self.digest}" if with_digest "#{qualified_target}#{digest_string}.css" end |
#stylesheet_filename_no_digest ⇒ Object
137 138 139 |
# File 'lib/stylesheet/manager/builder.rb', line 137 def stylesheet_filename_no_digest stylesheet_filename(_with_digest = false) end |
#stylesheet_fullpath ⇒ Object
85 86 87 |
# File 'lib/stylesheet/manager/builder.rb', line 85 def stylesheet_fullpath "#{cache_fullpath}/#{stylesheet_filename}" end |
#stylesheet_fullpath_no_digest ⇒ Object
101 102 103 |
# File 'lib/stylesheet/manager/builder.rb', line 101 def stylesheet_fullpath_no_digest "#{cache_fullpath}/#{stylesheet_filename_no_digest}" end |
#stylesheet_relpath ⇒ Object
113 114 115 |
# File 'lib/stylesheet/manager/builder.rb', line 113 def stylesheet_relpath "#{root_path}stylesheets/#{stylesheet_filename}" end |
#stylesheet_relpath_no_digest ⇒ Object
117 118 119 |
# File 'lib/stylesheet/manager/builder.rb', line 117 def stylesheet_relpath_no_digest "#{root_path}stylesheets/#{stylesheet_filename_no_digest}" end |
#theme_digest ⇒ Object
185 186 187 188 189 190 |
# File 'lib/stylesheet/manager/builder.rb', line 185 def theme_digest Digest::SHA1.hexdigest( scss_digest.to_s + color_scheme_digest.to_s + settings_digest + uploads_digest + current_hostname, ) end |
#uploads_digest ⇒ Object
228 229 230 231 232 233 234 |
# File 'lib/stylesheet/manager/builder.rb', line 228 def uploads_digest sha1s = [] (theme&.upload_fields || []).map { |upload_field| sha1s << upload_field.upload&.sha1 } Digest::SHA1.hexdigest(sha1s.compact.sort!.join("\n")) end |
#with_load_paths ⇒ Object
167 168 169 170 171 172 173 |
# File 'lib/stylesheet/manager/builder.rb', line 167 def with_load_paths if theme theme.with_scss_load_paths { |p| yield p } else yield nil end end |