sutty/app/models/site/static_file_migration.rb

124 lines
4.1 KiB
Ruby
Raw Normal View History

2019-11-14 17:27:24 +00:00
# frozen_string_literal: true
class Site
# Obtiene todos los archivos relacionados en artículos del sitio y los
# sube a Sutty de forma que los podamos seguir utilizando normalmente
# sin casos especiales (ej. soportar archivos locales al repositorio y
# remotos, alojados en Sutty)
#
# TODO: Convertir en reutilizable, por ejemplo correr en cada pull, no
# asumir que la migración se hizo una sola vez...
class StaticFileMigration
# Tipos de metadatos que contienen archivos
STATIC_TYPES = %w[file image].freeze
attr_reader :site
def initialize(site:)
@site = site
end
# Recorre todos los artículos cuyos layouts contengan campos con
# archivos estáticos
def migrate!
log = File.open(File.join(site.path, 'migration.log'), 'w')
modified = []
Dir.chdir site.path do
site.locales.each do |locale|
# Recorrer todos los documentos de todas las colecciones
site.posts(lang: locale).each do |doc|
# Ignoramos los documentos cuyo layout no contiene archivos
next unless layouts.include? doc.layout.name
# Buscamos todos los campos con archivos
fields.each do |field|
next unless doc.attribute? field
next unless doc.document.data.key? field.to_s
# Traemos los metadatos, en este punto, Sutty cree que el
# archivo está subido, porque es una string apuntando a un
# archivo.
metadata = doc.public_send(field)
next if metadata.value['path'].blank?
2021-02-16 21:08:42 +00:00
next if ActiveStorage::Blob.find_by(key: metadata.key_from_path)
2019-11-14 17:27:24 +00:00
path = Pathname.new(metadata.value['path'])
# Si no existe vaciamos el campo
2019-11-14 17:27:24 +00:00
unless path.exist?
metadata.value['path'] = nil
log.write "el archivo #{path} de #{doc.path.relative} no existe"
next
2019-11-14 17:27:24 +00:00
end
# Agregamos el archivo al sitio y se lo asignamos al campo
2020-11-20 17:09:02 +00:00
# XXX: No usamos ActionDispatch::Http::UploadedFile porque
# no tenemos forma de crear un Tempfile o equivalente a
# partir de un archivo que exista.
2019-11-14 17:27:24 +00:00
metadata.value['path'] = {
io: path.open,
filename: path.basename
}
# Copiar y analizar el archivo sincrónicamente
metadata.static_file.blob.upload path.open
metadata.static_file.blob.analyze
dest = Pathname.new(metadata.send(:relative_destination_path))
2020-11-20 17:09:02 +00:00
metadata.value['path'] = dest.to_s
2020-11-26 17:35:42 +00:00
metadata.send(:hardlink)
2019-11-14 17:27:24 +00:00
# Eliminamos el archivo original y lo vinculamos al subido
# para mantener la ruta y no romper el sitio
FileUtils.rm_f path
# XXX: Link simbólico o duro?
FileUtils.ln_s dest.relative_path_from(path.dirname), path
end
# Guardamos los cambios
2020-06-16 22:10:54 +00:00
log.write "#{doc.path.relative} no se pudo guardar\n" unless doc.save(validate: false)
2019-11-14 17:27:24 +00:00
modified << doc.path.absolute
end
end
end
log.close
return if modified.empty?
2019-11-14 17:27:24 +00:00
# TODO: Hacer la migración desde el servicio de creación de sitios?
site.repository.commit(file: modified,
message: I18n.t('sites.static_file_migration'),
usuarie: author)
end
private
def author
2020-06-16 22:10:54 +00:00
@author ||= GitAuthor.new email: "sutty@#{Site.domain}",
name: 'Sutty'
2019-11-14 17:27:24 +00:00
end
# Encuentra todos los layouts con campos estáticos
def layouts
@layouts ||= site.layouts.to_h.reject do |_, layout|
2019-11-14 17:27:24 +00:00
layout.metadata.select do |_, desc|
STATIC_TYPES.include? desc['type']
end.empty?
end.keys
end
# Encuentra todos los campos con archivos estáticos
def fields
@fields ||= layouts.map do |layout|
site.layouts[layout].metadata.select do |_, desc|
STATIC_TYPES.include? desc['type']
end.keys
end.flatten.uniq.map(&:to_sym)
end
end
end