lib/sitediff.rb in sitediff-0.0.6 vs lib/sitediff.rb in sitediff-1.0.0
- old
+ new
@@ -1,107 +1,140 @@
#!/bin/env ruby
# frozen_string_literal: true
require 'sitediff/config'
+require 'sitediff/diff'
require 'sitediff/fetch'
require 'sitediff/result'
+require 'sitediff/report'
require 'pathname'
require 'rainbow'
+require 'rubygems'
require 'yaml'
+# SiteDiff Object.
class SiteDiff
- # path to misc. static files (e.g. erb, css files)
- FILES_DIR = File.join(File.dirname(__FILE__), 'sitediff', 'files')
+ attr_reader :config, :results
- # subdirectory containing all failing diffs
- DIFFS_DIR = 'diffs'
+ # SiteDiff installation directory.
+ ROOT_DIR = File.dirname(File.dirname(__FILE__))
- # files in output
- FAILURES_FILE = 'failures.txt'
- REPORT_FILE = 'report.html'
- SETTINGS_FILE = 'settings.yaml'
+ # Path to misc files. Ex: *.erb, *.css.
+ FILES_DIR = File.join(File.dirname(__FILE__), 'sitediff', 'files')
- # label will be colorized and str will not be.
- # type dictates the color: can be :success, :error, or :failure
- def self.log(str, type = :info, label = nil)
- label = label ? "[sitediff] #{label}" : '[sitediff]'
- bg = fg = nil
- case type
- when :info
- bg = fg = nil
- when :diff_success
- bg = :green
+ # Logs a message.
+ #
+ # Label will be colorized and message will not.
+ # Type dictates the color: can be :success, :error, or :failure.
+ #
+ # TODO: Only print :debug messages in debug mode.
+ def self.log(message, type = :info, label = nil)
+ # Prepare label.
+ label ||= type unless type == :info
+ label = label.to_s
+ unless label.empty?
+ # Colorize label.
fg = :black
- when :diff_failure
- bg = :red
- when :warn
- bg = :yellow
- fg = :black
- when :error
- bg = :red
+ bg = :blue
+
+ case type
+ when :info
+ bg = :cyan
+ when :success
+ bg = :green
+ when :error
+ bg = :red
+ when :warning
+ bg = :yellow
+ end
+
+ label = '[' + label.to_s + ']'
+ label = Rainbow(label)
+ label = label.bg(bg) if bg
+ label = label.fg(fg) if fg
+
+ # Add a space after the label.
+ label += ' '
end
- label = Rainbow(label)
- label = label.bg(bg) if bg
- label = label.fg(fg) if fg
- puts label + ' ' + str
+
+ puts label + message
end
- attr_reader :config, :results
+ ##
+ # Returns the "before" site's URL.
+ #
+ # TODO: Remove in favor of config.before_url.
def before
@config.before['url']
end
+ ##
+ # Returns the "after" site's URL.
+ #
+ # TODO: Remove in favor of config.after_url.
def after
@config.after['url']
end
- def initialize(config, cache, concurrency, interval, verbose = true, debug = false)
+ # Initialize SiteDiff.
+ def initialize(config, cache, verbose = true, debug = false)
@cache = cache
@verbose = verbose
@debug = debug
- @interval = interval
+
# Check for single-site mode
validate_opts = {}
if !config.before['url'] && @cache.tag?(:before)
unless @cache.read_tags.include?(:before)
raise SiteDiffException,
"A cached 'before' is required for single-site mode"
end
validate_opts[:need_before] = false
end
config.validate(validate_opts)
-
- @concurrency = concurrency
+ # Configure diff.
+ Diff.diff_config(config)
@config = config
end
- # Sanitize HTML
+ # Sanitize HTML.
def sanitize(path, read_results)
%i[before after].map do |tag|
html = read_results[tag].content
+ # TODO: See why encoding is empty while running tests.
+ #
+ # The presence of an "encoding" value used to be used to determine
+ # if the sanitizer would be called. However, encoding turns up blank
+ # during rspec tests for some reason.
encoding = read_results[tag].encoding
- if encoding
- config = @config.send(tag)
- Sanitizer.new(html, config, path: path).sanitize
+ if encoding || html.length.positive?
+ section = @config.send(tag, true)
+ Sanitizer.new(html, section, path: path).sanitize
else
html
end
end
end
- # Process a set of read results
+ ##
+ # Process a set of read results.
+ #
+ # This is the callback that processes items fetched by the Fetcher.
def process_results(path, read_results)
- if (error = (read_results[:before].error || read_results[:after].error))
+ error = (read_results[:before].error || read_results[:after].error)
+ if error
diff = Result.new(path, nil, nil, nil, nil, error)
else
begin
- diff = Result.new(path,
- *sanitize(path, read_results),
- read_results[:before].encoding,
- read_results[:after].encoding,
- nil)
- rescue => e
+ diff = Result.new(
+ path,
+ *sanitize(path, read_results),
+ read_results[:before].encoding,
+ read_results[:after].encoding,
+ nil
+ )
+ rescue StandardError => e
raise if @debug
Result.new(path, nil, nil, nil, nil, "Sanitization error: #{e}")
end
end
@@ -112,62 +145,74 @@
next_diff.log(@verbose)
@ordered.shift
end
end
- # Perform the comparison, populate @results and return the number of failing
- # paths (paths with non-zero diff).
- def run(curl_opts = {}, debug = true)
+ ##
+ # Compute diff as per config.
+ #
+ # @return [Integer]
+ # Number of paths which have diffs.
+ def run
# Map of path -> Result object, populated by process_results
@results = {}
@ordered = @config.paths.dup
unless @cache.read_tags.empty?
- SiteDiff.log('Using sites from cache: ' +
- @cache.read_tags.sort.join(', '))
+ SiteDiff.log('Using sites from cache: ' + @cache.read_tags.sort.join(', '))
end
# TODO: Fix this after config merge refactor!
# Not quite right. We are not passing @config.before or @config.after
# so passing this instead but @config.after['curl_opts'] is ignored.
+ curl_opts = @config.setting :curl_opts
config_curl_opts = @config.before['curl_opts']
curl_opts = config_curl_opts.clone.merge(curl_opts) if config_curl_opts
- fetcher = Fetch.new(@cache, @config.paths, @interval, @concurrency, curl_opts, debug,
- before: before, after: after)
+ fetcher = Fetch.new(
+ @cache,
+ @config.paths,
+ @config.setting(:interval),
+ @config.setting(:concurrency),
+ curl_opts,
+ @debug,
+ before: @config.before_url,
+ after: @config.after_url
+ )
+
+ # Run the Fetcher with "process results" as a callback.
fetcher.run(&method(:process_results))
# Order by original path order
- @results = @config.paths.map { |p| @results[p] }
+ @results = @config.paths.map { |path| @results[path] }
results.map { |r| r unless r.success? }.compact.length
end
- # Dump results to disk
- def dump(dir, report_before, report_after)
- report_before ||= before
- report_after ||= after
- dir = Pathname.new(dir)
- dir.mkpath unless dir.directory?
-
- # store diffs of each failing case, first wipe out existing diffs
- diff_dir = dir + DIFFS_DIR
- diff_dir.rmtree if diff_dir.exist?
- results.each { |r| r.dump(dir) if r.status == Result::STATUS_FAILURE }
- SiteDiff.log "All diff files were dumped inside #{dir.expand_path}"
-
- # store failing paths
- failures = dir + FAILURES_FILE
- SiteDiff.log "Writing failures to #{failures.expand_path}"
- failures.open('w') do |f|
- results.each { |r| f.puts r.path unless r.success? }
+ ##
+ # Get a reporter object to help with report generation.
+ def report
+ if @results.nil?
+ raise SiteDiffException(
+ 'No results detected. Run SiteDiff.run before SiteDiff.report.'
+ )
end
- # create report of results
- report = Diff.generate_html_report(results, report_before, report_after,
- @cache)
- dir.+(REPORT_FILE).open('w') { |f| f.write(report) }
+ Report.new(@config, @cache, @results)
+ end
- # serve some settings
- settings = { 'before' => report_before, 'after' => report_after,
- 'cached' => %w[before after] }
- dir.+(SETTINGS_FILE).open('w') { |f| YAML.dump(settings, f) }
+ ##
+ # Get SiteDiff gemspec.
+ def self.gemspec
+ file = ROOT_DIR + '/sitediff.gemspec'
+ Gem::Specification.load(file)
+ end
+
+ ##
+ # Ensures that a directory exists and returns a Pathname for it.
+ #
+ # @param [String] dir
+ # path/to/directory
+ def self.ensure_dir(dir)
+ dir = Pathname.new(dir) unless dir.is_a? Pathname
+ dir.mkpath unless dir.directory?
+ dir
end
end