diff --git a/app/lib/active_storage/service/jekyll_service.rb b/app/lib/active_storage/service/jekyll_service.rb index 88ffa83c..e6c5fda6 100644 --- a/app/lib/active_storage/service/jekyll_service.rb +++ b/app/lib/active_storage/service/jekyll_service.rb @@ -4,11 +4,6 @@ module ActiveStorage class Service # Sube los archivos a cada repositorio y los agrega al LFS de su # repositorio git. - # - # @todo: Implementar LFS. No nos gusta mucho la idea porque duplica - # el espacio en disco, pero es la única forma que tenemos (hasta que - # implementemos IPFS) para poder transferir los archivos junto con el - # sitio. class JekyllService < Service::DiskService # Genera un servicio para un sitio determinado # @@ -27,7 +22,10 @@ module ActiveStorage # @param :checksum [String] def upload(key, io, checksum: nil, **) instrument :upload, key: key, checksum: checksum do - IO.copy_stream(io, make_path_for(key)) unless exist?(key) + unless exist?(key) + IO.copy_stream(io, make_path_for(key)) + LfsObjectService.new(site: site, blob: blob_for(key)).process + end ensure_integrity_of(key, checksum) if checksum end end @@ -79,7 +77,7 @@ module ActiveStorage # @param :key [String] # @return [String] def filename_for(key) - ActiveStorage::Blob.where(key: key).limit(1).pluck(:filename).first.tap do |filename| + blob_for(key).filename.to_s.tap do |filename| raise ArgumentError, "Filename for key #{key} is blank" if filename.blank? end end @@ -91,6 +89,15 @@ module ActiveStorage def path_for(key) File.join root, folder_for(key), filename_for(key) end + + # @return [Site] + def site + @site ||= Site.find_by_name(name) + end + + def blob_for(key) + ActiveStorage::Blob.find_by(key: key, service_name: name) + end end end end diff --git a/app/models/site/repository.rb b/app/models/site/repository.rb index f63288d4..62e4c45e 100644 --- a/app/models/site/repository.rb +++ b/app/models/site/repository.rb @@ -117,6 +117,9 @@ class Site def commit(file:, usuarie:, message:, remove: false) file = [file] unless file.respond_to? :each + # Cargar el árbol actual + rugged.index.read_tree rugged.head.target.tree + file.each do |f| remove ? rm(f) : add(f) end diff --git a/app/services/lfs_object_service.rb b/app/services/lfs_object_service.rb new file mode 100644 index 00000000..bb62301d --- /dev/null +++ b/app/services/lfs_object_service.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +# Representa un objeto git LFS +class LfsObjectService + attr_reader :site, :blob + + # @param :site [Site] + # @param :blob [ActiveStorage::Blob] + def initialize(site:, blob:) + @site = site + @blob = blob + end + + def process + # Crear el directorio + FileUtils.mkdir_p(File.dirname(object_path)) + + # Mover el archivo + FileUtils.mv(path, object_path) unless File.exist? object_path + + # Crear el pointer + Site::Writer.new(site: site, file: path, content: pointer).save + + # Commitear el pointer + site.repository.commit(file: path, usuarie: author, message: File.basename(path)) + + # Eliminar el pointer + FileUtils.rm(path) + + # Hacer link duro del objeto al archivo + FileUtils.ln(object_path, path) + end + + # @return [String] + def path + @path ||= blob.service.path_for(blob.key) + end + + # @return [String] + def digest + @digest ||= Digest::SHA256.file(path).hexdigest + end + + # @return [String] + def object_path + @object_path ||= File.join(site.path, '.git', 'lfs', 'objects', digest[0..1], digest[2..3], digest) + end + + # @return [Integer] + def size + @size ||= File.size(File.exist?(object_path) ? object_path : path) + end + + # @return [String] + def pointer + @pointer ||= + <<~POINTER + version https://git-lfs.github.com/spec/v1 + oid sha256:#{digest} + size #{size} + POINTER + end + + def author + @author ||= GitAuthor.new email: "disk_service@#{Site.domain}", name: 'DiskService' + end +end