update concerns

This commit is contained in:
2026-08-02 12:58:31 +02:00
parent 4cc05ee586
commit 9db8ff189c
13 changed files with 179 additions and 234 deletions
@@ -0,0 +1,45 @@
require "zip"
require "fileutils"
module SoftwareUpdater
module ArchiveExtraction
private
def base_path
@base_path ||= ENV.fetch("FILE_CONTAINER_PATH", "/softwares")
end
def full_path(filename)
File.join(base_path, filename)
end
def dir_exists?(dirname)
File.directory?(full_path(dirname))
end
def delete_dir(dirname)
FileUtils.rm_rf(full_path(dirname))
end
def create_dir(dirname)
FileUtils.mkdir_p(full_path(dirname))
end
def unzip_file(zip_filename, dest_dirname)
dest = full_path(dest_dirname)
Zip::File.open(full_path(zip_filename)) do |zip|
zip.each do |entry|
entry_dest = File.join(dest, entry.name)
FileUtils.mkdir_p(File.dirname(entry_dest))
entry.extract(entry_dest) { true }
end
end
end
def extract_zip_to_dir(zip_file, dir_name)
delete_dir(dir_name) if dir_exists?(dir_name)
create_dir(dir_name)
unzip_file(zip_file, dir_name)
end
end
end
@@ -0,0 +1,14 @@
require "json"
module SoftwareUpdater
module MetadataParsing
METADATA_KEYS = %i[name title author desc site repo license].freeze
private
def parse_json_metadata(path)
raw = JSON.parse(File.read(path), symbolize_names: true)
raw.slice(*METADATA_KEYS)
end
end
end
@@ -0,0 +1,27 @@
module SoftwareUpdater
module SoftwarePersistence
private
def update_or_create_software(attrs)
software = Software.unscoped.find_or_initialize_by(name: attrs[:name])
software.assign_attributes(attrs.except(:name))
software.deleted_at = nil
software.save!
software
end
def upsert_external_link(software_id, label, url)
link = ExternalLink.unscoped.find_or_initialize_by(software_id: software_id, label: label)
link.url = url
link.deleted_at = nil
link.save!
end
def create_release_if_not_exists(attrs)
existing = Release.unscoped.find_by(software_id: attrs[:software_id], version: attrs[:version])
return existing if existing
Release.create!(attrs)
end
end
end
@@ -0,0 +1,48 @@
module SoftwareUpdater
module Updatable
extend ActiveSupport::Concern
include ArchiveExtraction
include MetadataParsing
include SoftwarePersistence
class_methods do
def platform(value = nil)
@platform = value if value
@platform ||= name.demodulize.delete_suffix("Service").downcase
end
end
def update(name, version)
versioned = "#{name}-#{version}"
prepare_files(versioned)
metadata = parse_metadata(versioned)
site_url = metadata.delete(:site)
repo_url = metadata.delete(:repo)
ActiveRecord::Base.transaction do
software = update_or_create_software(metadata.merge(platform: self.class.platform))
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
upsert_external_link(software.id, "Repository", repo_url) if repo_url.present?
create_release_if_not_exists(
{ software_id: software.id, version: version }.merge(release_paths(versioned))
)
end
end
private
def prepare_files(versioned)
extract_zip_to_dir("#{versioned}.html.zip", versioned)
end
def parse_metadata(versioned)
parse_json_metadata(full_path("#{versioned}.metadata.json"))
end
def release_paths(versioned)
{ html_folder_path: full_path(versioned) }
end
end
end
@@ -1,73 +0,0 @@
require "zip"
require "json"
require "fileutils"
module SoftwareUpdater
class BaseService
def initialize
@base_path = ENV.fetch("FILE_CONTAINER_PATH", "/softwares")
end
private
def full_path(filename)
File.join(@base_path, filename)
end
def dir_exists?(dirname)
File.directory?(full_path(dirname))
end
def delete_dir(dirname)
FileUtils.rm_rf(full_path(dirname))
end
def create_dir(dirname)
FileUtils.mkdir_p(full_path(dirname))
end
def unzip_file(zip_filename, dest_dirname)
dest = full_path(dest_dirname)
Zip::File.open(full_path(zip_filename)) do |zip|
zip.each do |entry|
entry_dest = File.join(dest, entry.name)
FileUtils.mkdir_p(File.dirname(entry_dest))
entry.extract(entry_dest) { true }
end
end
end
def extract_zip_to_dir(zip_file, dir_name)
delete_dir(dir_name) if dir_exists?(dir_name)
create_dir(dir_name)
unzip_file(zip_file, dir_name)
end
def parse_json_metadata(path)
raw = JSON.parse(File.read(path), symbolize_names: true)
raw.slice(:name, :title, :author, :desc, :site, :repo, :license)
end
def update_or_create_software(attrs)
software = Software.unscoped.find_or_initialize_by(name: attrs[:name])
software.assign_attributes(attrs.except(:name))
software.deleted_at = nil
software.save!
software
end
def upsert_external_link(software_id, label, url)
link = ExternalLink.unscoped.find_or_initialize_by(software_id: software_id, label: label)
link.url = url
link.deleted_at = nil
link.save!
end
def create_release_if_not_exists(attrs)
existing = Release.unscoped.find_by(software_id: attrs[:software_id], version: attrs[:version])
return existing if existing
Release.create!(attrs)
end
end
end
@@ -1,24 +1,5 @@
module SoftwareUpdater
class BevyService < BaseService
def update(name, version)
versioned = "#{name}-#{version}"
extract_zip_to_dir("#{versioned}.html.zip", versioned)
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
site_url = metadata.delete(:site)
repo_url = metadata.delete(:repo)
ActiveRecord::Base.transaction do
software = update_or_create_software(metadata.merge(platform: "bevy"))
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
upsert_external_link(software.id, "Repository", repo_url) if repo_url.present?
create_release_if_not_exists(
software_id: software.id,
version: version,
html_folder_path: full_path(versioned)
)
end
end
class BevyService
include Updatable
end
end
@@ -1,23 +1,15 @@
module SoftwareUpdater
class C64Service < BaseService
def update(name, version)
versioned = "#{name}-#{version}"
class C64Service
include Updatable
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
site_url = metadata.delete(:site)
repo_url = metadata.delete(:repo)
private
ActiveRecord::Base.transaction do
software = update_or_create_software(metadata.merge(platform: "c64"))
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
upsert_external_link(software.id, "Repository", repo_url) if repo_url.present?
def prepare_files(_versioned)
# a c64 buildhez nem tartozik html zip, csak a .prg fájl
end
create_release_if_not_exists(
software_id: software.id,
version: version,
cartridge_path: full_path("#{versioned}.prg")
)
end
def release_paths(versioned)
{ cartridge_path: full_path("#{versioned}.prg") }
end
end
end
@@ -1,24 +1,5 @@
module SoftwareUpdater
class EbitengineService < BaseService
def update(name, version)
versioned = "#{name}-#{version}"
extract_zip_to_dir("#{versioned}.html.zip", versioned)
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
site_url = metadata.delete(:site)
repo_url = metadata.delete(:repo)
ActiveRecord::Base.transaction do
software = update_or_create_software(metadata.merge(platform: "ebitengine"))
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
upsert_external_link(software.id, "Repository", repo_url) if repo_url.present?
create_release_if_not_exists(
software_id: software.id,
version: version,
html_folder_path: full_path(versioned)
)
end
end
class EbitengineService
include Updatable
end
end
@@ -1,24 +1,5 @@
module SoftwareUpdater
class GodotService < BaseService
def update(name, version)
versioned = "#{name}-#{version}"
extract_zip_to_dir("#{versioned}.html.zip", versioned)
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
site_url = metadata.delete(:site)
repo_url = metadata.delete(:repo)
ActiveRecord::Base.transaction do
software = update_or_create_software(metadata.merge(platform: "godot"))
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
upsert_external_link(software.id, "Repository", repo_url) if repo_url.present?
create_release_if_not_exists(
software_id: software.id,
version: version,
html_folder_path: full_path(versioned)
)
end
end
class GodotService
include Updatable
end
end
@@ -1,24 +1,5 @@
module SoftwareUpdater
class LoveService < BaseService
def update(name, version)
versioned = "#{name}-#{version}"
extract_zip_to_dir("#{versioned}.html.zip", versioned)
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
site_url = metadata.delete(:site)
repo_url = metadata.delete(:repo)
ActiveRecord::Base.transaction do
software = update_or_create_software(metadata.merge(platform: "love"))
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
upsert_external_link(software.id, "Repository", repo_url) if repo_url.present?
create_release_if_not_exists(
software_id: software.id,
version: version,
html_folder_path: full_path(versioned)
)
end
end
class LoveService
include Updatable
end
end
@@ -1,24 +1,5 @@
module SoftwareUpdater
class PhaserService < BaseService
def update(name, version)
versioned = "#{name}-#{version}"
extract_zip_to_dir("#{versioned}.html.zip", versioned)
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
site_url = metadata.delete(:site)
repo_url = metadata.delete(:repo)
ActiveRecord::Base.transaction do
software = update_or_create_software(metadata.merge(platform: "phaser"))
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
upsert_external_link(software.id, "Repository", repo_url) if repo_url.present?
create_release_if_not_exists(
software_id: software.id,
version: version,
html_folder_path: full_path(versioned)
)
end
end
class PhaserService
include Updatable
end
end
@@ -1,34 +1,27 @@
module SoftwareUpdater
class Tic80Service < BaseService
def update(name, version)
versioned = "#{name}-#{version}"
docs_dir = "#{versioned}-docs"
extract_zip_to_dir("#{versioned}.html.zip", versioned)
extract_zip_to_dir("#{versioned}-docs.zip", docs_dir)
metadata = parse_lua_metadata(full_path("#{versioned}.lua"))
site_url = metadata.delete(:site)
repo_url = metadata.delete(:repo)
ActiveRecord::Base.transaction do
software = update_or_create_software(metadata.merge(platform: "tic80"))
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
upsert_external_link(software.id, "Repository", repo_url) if repo_url.present?
create_release_if_not_exists(
software_id: software.id,
version: version,
cartridge_path: full_path("#{versioned}.tic"),
source_path: full_path("#{versioned}.lua"),
html_folder_path: full_path(versioned),
docs_folder_path: full_path(docs_dir)
)
end
end
class Tic80Service
include Updatable
private
def prepare_files(versioned)
extract_zip_to_dir("#{versioned}.html.zip", versioned)
extract_zip_to_dir("#{versioned}-docs.zip", "#{versioned}-docs")
end
def parse_metadata(versioned)
parse_lua_metadata(full_path("#{versioned}.lua"))
end
def release_paths(versioned)
{
cartridge_path: full_path("#{versioned}.tic"),
source_path: full_path("#{versioned}.lua"),
html_folder_path: full_path(versioned),
docs_folder_path: full_path("#{versioned}-docs")
}
end
def parse_lua_metadata(source_path)
metadata = {}
File.foreach(source_path) do |line|
@@ -39,7 +32,7 @@ module SoftwareUpdater
value = parts[1].strip
metadata[key] = value
end
metadata.slice(:name, :title, :author, :desc, :site, :repo, :license)
metadata.slice(*MetadataParsing::METADATA_KEYS)
end
end
end
+6 -12
View File
@@ -1,17 +1,11 @@
class UpdateService
PLATFORM_SERVICES = {
"tic80" => "SoftwareUpdater::Tic80Service",
"ebitengine" => "SoftwareUpdater::EbitengineService",
"love" => "SoftwareUpdater::LoveService",
"c64" => "SoftwareUpdater::C64Service",
"godot" => "SoftwareUpdater::GodotService",
"bevy" => "SoftwareUpdater::BevyService",
"phaser" => "SoftwareUpdater::PhaserService"
}.freeze
SUPPORTED_PLATFORMS = %w[tic80 ebitengine love c64 godot bevy phaser].freeze
def update(input)
service_class = PLATFORM_SERVICES[input.platform]
raise ArgumentError, "Unsupported platform: #{input.platform}" unless service_class
service_class.constantize.new.update(input.name, input.version)
unless SUPPORTED_PLATFORMS.include?(input.platform)
raise ArgumentError, "Unsupported platform: #{input.platform}"
end
"SoftwareUpdater::#{input.platform.camelize}Service".constantize.new.update(input.name, input.version)
end
end