diff --git a/app/models/site.rb b/app/models/site.rb index 7b26024a..dd86a9f8 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -70,7 +70,7 @@ class Site < ApplicationRecord # Este sitio acepta invitadxs? def invitadxs? - jekyll.config.fetch('invitadxs', false) + config.fetch('invitadxs', false) end def cover @@ -84,12 +84,12 @@ class Site < ApplicationRecord # Define si el sitio tiene un glosario def glossary? - jekyll.config.fetch('glossary', false) + config.fetch('glossary', false) end # Obtiene la lista de traducciones actuales def translations - @jekyll.config.dig('i18n') || [] + config.fetch('i18n', []) end # Devuelve el idioma por defecto del sitio @@ -146,14 +146,10 @@ class Site < ApplicationRecord end def config - if @jekyll.config.empty? - read - Rails.logger.info 'Leyendo config' - end - - @jekyll.config + @config ||= Site::Config.new(self) end + # TODO: Cambiar a Site::Config apenas empecemos a testear esto def collections_names @jekyll.config['collections'].keys end @@ -270,31 +266,14 @@ class Site < ApplicationRecord File.join('/', 'sites', id, path.gsub('..', '')) end - def get_url_from_site(path) - "https://#{name}#{path}" - end - # El directorio donde se almacenan los sitios def self.site_path File.join(Rails.root, '_sites') end - # El directorio de los sitios de una usuaria - # - # Los sitios se organizan por usuaria, entonces los sitios que - # administra pueden encontrarse directamente en su directorio. - # - # Si comparten gestión con otras usuarias, se hacen links simbólicos - # entre sí. - def self.site_path_for(site) - File.join(Site.site_path, site) - end - - # Comprueba que el directorio parezca ser de jekyll - def self.jekyll?(dir) - File.directory?(dir) && File.exist?(File.join(dir, '_config.yml')) - end - + # TODO: En lugar de leer todo junto de una vez, extraer la carga de + # documentos de Jekyll hacia Sutty para que podamos leer los datos que + # necesitamos. def self.load_jekyll(path) # Pasamos destination porque configuration() toma el directorio # actual y se mezclan :/ diff --git a/app/models/site/config.rb b/app/models/site/config.rb new file mode 100644 index 00000000..34b64696 --- /dev/null +++ b/app/models/site/config.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +class Site + # Representa la configuración del sitio de forma que podamos leer y + # escribir en el archivo _config.yml + class Config < OpenStruct + def initialize(site) + # Iniciar el OpenStruct con el sitio + super(site: site) + + read + end + + # Obtener un valor por defecto a partir de la configuración + def fetch(key, default) + send(:[], key) || default + end + + # Leer el archivo de configuración y setear los atributos en el + # objeto actual, creando los metodos de ostruct + def read + YAML.safe_load(File.read(path)).each do |key, value| + send("#{key}=".to_sym, value) + end + end + + # Escribe los cambios en el repositorio + # + # TODO: Convertir en una clase intermedia que también se encargue de + # guardar en git + def write + r = File.open(path, File::RDWR | File::CREAT, 0o640) do |f| + # Bloquear el archivo para que no sea accedido por otro + # proceso u otra editora + f.flock(File::LOCK_EX) + + # Empezar por el principio + f.rewind + + # Escribir el contenido en YAML + f.write(content.to_yaml) + + # Eliminar el resto + f.flush + f.truncate(f.pos) + end + + r.zero? + end + + # Obtener el contenido de la configuración como un hash, sin el + # sitio correspondiente. + def content + h = to_h.stringify_keys + h.delete 'site' + + h + end + + # Obtener la ruta donde se encuentra la configuración. + def path + File.join site.path, '_config.yml' + end + end +end diff --git a/app/models/site/repository.rb b/app/models/site/repository.rb index e8d49c09..e182a2a9 100644 --- a/app/models/site/repository.rb +++ b/app/models/site/repository.rb @@ -18,6 +18,10 @@ class Site end # Trae los cambios del repositorio de origen sin aplicarlos y + # devuelve la cantidad de commits pendientes. + # + # XXX: Prestar atención a la velocidad de respuesta cuando tengamos + # repositorios remotos. def fetch if remote.check_connection :fetch @changes = rugged.fetch(remote)[:received_objects] diff --git a/bin/bundle b/bin/bundle index f19acf5b..6965387f 100755 --- a/bin/bundle +++ b/bin/bundle @@ -1,3 +1,109 @@ #!/usr/bin/env ruby -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -load Gem.bin_path('bundler', 'bundle') +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__) + end + + def env_var_version + ENV['BUNDLER_VERSION'] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update` + + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + + bundler_version = Regexp.last_match(1) || '>= 0.a' + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV['BUNDLE_GEMFILE'] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path('../Gemfile', __dir__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + + Regexp.last_match(1) + end + + def bundler_version + @bundler_version ||= begin + env_var_version || cli_arg_version || + lockfile_version || "#{Gem::Requirement.default}.a" + end + end + + def load_bundler! + ENV['BUNDLE_GEMFILE'] ||= gemfile + + # must dup string for RG < 1.8 compatibility + activate_bundler(bundler_version.dup) + end + + def activate_bundler(bundler_version) + if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new('2.0') + bundler_version = '< 2' + end + gem_error = activation_error_handling do + gem 'bundler', bundler_version + end + return if gem_error.nil? + + require_error = activation_error_handling do + require 'bundler/version' + end + return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + + warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script? diff --git a/test/models/site/config_test.rb b/test/models/site/config_test.rb new file mode 100644 index 00000000..1ecbaba7 --- /dev/null +++ b/test/models/site/config_test.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +class ConfigText < ActiveSupport::TestCase + setup do + @rol = create :rol + @site = @rol.site + @usuarie = @rol.usuarie + end + + teardown do + @site.destroy + end + + test 'se puede leer' do + assert @site.config.is_a?(Site::Config) + assert_equal @site, @site.config.site + assert @site.config.plugins.count.positive? + end + + test 'se puede escribir' do + assert_nothing_raised do + @site.config.name = 'Test' + @site.config.lang = 'es' + end + + assert @site.config.write + + config = Site::Config.new(@site) + + assert_equal 'Test', config.name + assert_equal 'es', config.lang + end + + test 'se puede obtener información' do + assert @site.config.fetch('noexiste', true) + assert @site.config.fetch('sass', false) + end +end