mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-22 23:36:21 +00:00
180 lines
5.6 KiB
Ruby
180 lines
5.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Site
|
|
# Indexa todos los artículos de un sitio
|
|
#
|
|
# TODO: Hacer opcional
|
|
module Index
|
|
extend ActiveSupport::Concern
|
|
|
|
included do
|
|
has_many :indexed_posts, dependent: :destroy
|
|
|
|
MODIFIED_STATUSES = %i[added modified renamed].freeze
|
|
LOCALE_FROM_PATH = /\A_/.freeze
|
|
|
|
def blob_service
|
|
@blob_service ||= ActiveStorage::Service::JekyllService.build_for_site(site: self)
|
|
end
|
|
|
|
def index_posts!
|
|
Site.transaction do
|
|
docs.each(&:index!)
|
|
|
|
update(last_indexed_commit: repository.head_commit.oid)
|
|
end
|
|
end
|
|
|
|
# Encuentra los artículos modificados entre dos commits y los
|
|
# reindexa.
|
|
def reindex_changes!
|
|
return unless reindexable?
|
|
|
|
Site.transaction do
|
|
remove_deleted_posts!
|
|
reindex_modified_posts!
|
|
|
|
update(last_indexed_commit: repository.head_commit.oid)
|
|
end
|
|
end
|
|
|
|
# No hacer nada si el repositorio no cambió o no hubo cambios
|
|
# necesarios
|
|
def reindexable?
|
|
return false if last_indexed_commit.blank?
|
|
return false if last_indexed_commit == repository.head_commit.oid
|
|
|
|
!indexable_posts.empty?
|
|
end
|
|
|
|
private
|
|
|
|
# Trae el último commit indexado desde el repositorio
|
|
#
|
|
# @return [Rugged::Commit]
|
|
def indexed_commit
|
|
@indexed_commit ||= repository.rugged.lookup(last_indexed_commit)
|
|
end
|
|
|
|
# Calcula la diferencia entre el último commit indexado y el
|
|
# actual
|
|
#
|
|
# XXX: Esto no tiene en cuenta modificaciones en la historia como
|
|
# cambio de ramas, reverts y etc, solo asume que se mueve hacia
|
|
# adelante en la misma rama o las dos ramas están relacionadas.
|
|
#
|
|
# @return [Rugged::Diff]
|
|
def diff_with_head
|
|
@diff_with_head ||= indexed_commit.diff(repository.head_commit)
|
|
end
|
|
|
|
# Obtiene todos los archivos a reindexar
|
|
#
|
|
# @return [Array<Rugged::Diff::Delta>]
|
|
def indexable_posts
|
|
@indexable_posts ||=
|
|
diff_with_head.each_delta.select do |delta|
|
|
locales.any? do |locale|
|
|
delta.old_file[:path].start_with? "_#{locale}/"
|
|
end
|
|
end
|
|
end
|
|
|
|
# Encuentra todos los archivos estáticos a reindexar, si fueron
|
|
# borrados necesitamos saber la ubicación anterior, si son nuevos,
|
|
# la nueva.
|
|
#
|
|
# @return [Array<Rugged::Diff::Delta>]
|
|
def indexable_static_files
|
|
@indexable_static_files ||=
|
|
diff_with_head.each_delta.select do |delta|
|
|
(
|
|
delta.status == :deleted &&
|
|
delta.old_file[:path].start_with?('public/')
|
|
) || delta.new_file[:path].start_with?('public/')
|
|
end
|
|
end
|
|
|
|
# Elimina los artículos eliminados o que cambiaron de ubicación
|
|
# del índice
|
|
def remove_deleted_posts!
|
|
indexable_posts.select(&:deleted?).each do |delta|
|
|
locale, path = locale_and_path_from(delta.old_file[:path])
|
|
|
|
indexed_posts.destroy_by(locale: locale, path: path).tap do |destroyed_posts|
|
|
next unless destroyed_posts.empty?
|
|
|
|
Rails.logger.info I18n.t('indexed_posts.deleted', site: name, path: path, records: destroyed_posts.count)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Elimina de ActiveStorage los archivos borrados, renombrados o
|
|
# modificados, para poder recalcular su contenido y nueva
|
|
# ubicación.
|
|
#
|
|
# Los renombrados o modificados se vuelven a crear en
|
|
# reindex_modified_static_files!
|
|
def remove_deleted_or_renamed_static_files!
|
|
indexable_static_files.select do |delta|
|
|
delta.deleted? || delta.modified? || delta.renamed?
|
|
end.each do |delta|
|
|
key = blob_service.key_from_path(delta.old_file[:path])
|
|
|
|
static_files.blobs.find_by(service_name: name, key: key).tap do |blob|
|
|
next unless blob
|
|
|
|
transaction do
|
|
static_files.where(blob_id: blob.id).destroy_all
|
|
blob.destroy
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# Reindexa los archivos estáticos modificados
|
|
def reindex_modified_static_files!
|
|
indexable_static_files.select do |delta|
|
|
MODIFIED_STATUSES.include?(delta.status) || delta.renamed?
|
|
end.each do |delta|
|
|
transaction do
|
|
path = blob_service.absolute_path_for(delta.new_file[:path].sub(%r{\Apublic/}, ''))
|
|
key = blob_service.key_from_path(path)
|
|
pathname = Pathname.new(path)
|
|
blob = ActiveStorage::Blob.create_after_unfurling!(key: key, io: pathname.open, filename: pathname.basename, service_name: name)
|
|
|
|
ActiveStorage::Attachment.create!(name: 'static_files', record: self, blob: blob)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Reindexa artículos que cambiaron de ubicación, se agregaron
|
|
# o fueron modificados
|
|
def reindex_modified_posts!
|
|
indexable_posts.select do |delta|
|
|
MODIFIED_STATUSES.include? delta.status
|
|
end.each do |delta|
|
|
locale, path = locale_and_path_from(delta.new_file[:path])
|
|
|
|
posts(lang: locale).find(path).index!
|
|
end
|
|
end
|
|
|
|
# Obtiene el idioma y la ruta del post a partir de la ubicación en
|
|
# el disco.
|
|
#
|
|
# Las rutas vienen en ASCII-9BIT desde Rugged, pero en realidad
|
|
# son UTF-8
|
|
#
|
|
# @return [Array<String>]
|
|
def locale_and_path_from(path)
|
|
locale, path = path.force_encoding('utf-8').split(File::SEPARATOR, 2)
|
|
|
|
[
|
|
locale.sub(LOCALE_FROM_PATH, ''),
|
|
File.basename(path, '.*')
|
|
]
|
|
end
|
|
end
|
|
end
|
|
end
|