vite_ruby/lib/vite_ruby/build.rb
# frozen_string_literal: true
require 'json'
require 'time'
# Internal: Value object with information about the last build.
ViteRuby::Build = Struct.new(:success, :timestamp, :vite_ruby, :digest, :current_digest, :last_build_path, :errors, keyword_init: true) do
class << self
# Internal: Combines information from a previous build with the current digest.
def from_previous(last_build_path, current_digest)
new(
**parse_metadata(last_build_path),
current_digest: current_digest,
last_build_path: last_build_path,
)
end
private
# Internal: Reads metadata recorded on the last build, if it exists.
def parse_metadata(pathname)
return default_metadata unless pathname.exist?
JSON.parse(pathname.read.to_s).transform_keys(&:to_sym).slice(*members)
rescue JSON::JSONError, Errno::ENOENT, Errno::ENOTDIR
default_metadata
end
# Internal: To make it evident that there's no last build in error messages.
def default_metadata
{ timestamp: 'never', digest: 'none' }
end
end
# Internal: A build is considered stale when watched files have changed since
# the last build, or when a certain time has ellapsed in case of failure.
def stale?
digest != current_digest || retry_failed? || vite_ruby != ViteRuby::VERSION
end
# Internal: A build is considered fresh if watched files have not changed, or
# the last failed build happened recently.
def fresh?
!stale?
end
# Internal: To avoid cascading build failures, if the last build failed and it
# happened within a short time window, a new build should not be triggered.
def retry_failed?
!success && Time.parse(timestamp) + 3 < Time.now # 3 seconds
rescue ArgumentError
true
end
# Internal: Returns a new build with the specified result.
def with_result(**attrs)
self.class.new(
**attrs,
timestamp: Time.now.strftime('%F %T'),
vite_ruby: ViteRuby::VERSION,
digest: current_digest,
current_digest: current_digest,
last_build_path: last_build_path,
)
end
# Internal: Writes the result of the new build to a local file.
def write_to_cache
last_build_path.write to_json
end
# Internal: Returns a JSON string with the metadata of the build.
def to_json(*_args)
JSON.pretty_generate(
success: success,
errors: errors,
timestamp: timestamp,
vite_ruby: vite_ruby,
digest: digest,
)
end
end