mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-04 05:09:20 +08:00
Ruby's compact module syntax (`module Migrations::Database::Schema::DSL`) breaks lexical constant lookup — `Module.nesting` only includes the innermost constant, so every cross-module reference must be fully qualified. In practice this means writing `Migrations::Database::Schema::Helpers` even when you're already inside `Migrations::Database::Schema`. Nested module definitions restore the full nesting chain, which brings several practical benefits: - **Less verbose code**: references like `Schema::Helpers`, `Database::IntermediateDB`, or `Converters::Base::ProgressStep` work without repeating the full path from root - **Easier to write new code**: contributors don't need to remember which prefixes are required — if you're inside the namespace, short names just work - **Fewer aliasing workarounds**: removes the need for constants like `MappingType = Migrations::Importer::MappingType` that existed solely to shorten references - **Standard Ruby style**: consistent with how most Ruby projects and gems structure their namespaces The diff is large but mechanical — no logic changes, just module wrapping and shortening references that the nesting now resolves. Generated code (intermediate_db models/enums) keeps fully qualified references like `Migrations::Database.format_*` since it must work regardless of the configured output namespace. - Convert 138 lib files from compact to nested module definitions - Remove now-redundant fully qualified prefixes and aliases - Update model and enum writers to generate nested modules with correct indentation - Regenerate all intermediate_db models and enums
88 lines
2.4 KiB
Ruby
88 lines
2.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Migrations
|
|
module Uploader
|
|
module Tasks
|
|
class Fixer < Base
|
|
def run!
|
|
return if max_count.zero?
|
|
|
|
puts "Fixing missing uploads..."
|
|
|
|
status_thread = start_status_thread
|
|
consumer_threads = start_consumer_threads
|
|
producer_thread = start_producer_thread
|
|
|
|
producer_thread.join
|
|
work_queue.close
|
|
consumer_threads.each(&:join)
|
|
status_queue.close
|
|
status_thread.join
|
|
end
|
|
|
|
private
|
|
|
|
def max_count
|
|
@max_count ||=
|
|
uploads_db.db.query_single_splat(
|
|
"SELECT COUNT(*) FROM uploads WHERE upload IS NOT NULL",
|
|
)
|
|
end
|
|
|
|
def enqueue_jobs
|
|
uploads_db
|
|
.db
|
|
.query(
|
|
"SELECT id, upload FROM uploads WHERE upload IS NOT NULL ORDER BY rowid DESC",
|
|
) { |row| work_queue << row }
|
|
end
|
|
|
|
def instantiate_task_resource
|
|
OpenStruct.new(url: "")
|
|
end
|
|
|
|
def handle_status_update(result)
|
|
@current_count += 1
|
|
|
|
case result[:status]
|
|
when :ok
|
|
# ignore
|
|
when :error
|
|
@error_count += 1
|
|
puts " Error in #{result[:id]}"
|
|
when :missing
|
|
@missing_count += 1
|
|
puts " Missing #{result[:id]}"
|
|
|
|
uploads_db.db.execute("DELETE FROM uploads WHERE id = ?", result[:id])
|
|
Upload.delete_by(id: result[:upload_id])
|
|
end
|
|
end
|
|
|
|
def process_upload(row, fake_upload)
|
|
upload = JSON.parse(row[:upload], symbolize_names: true)
|
|
fake_upload.url = upload[:url]
|
|
path = add_multisite_prefix(discourse_store.get_path_for_upload(fake_upload))
|
|
|
|
status = file_exists?(path) ? :ok : :missing
|
|
|
|
update_status_queue(row, upload, status)
|
|
rescue StandardError => error
|
|
puts error.message
|
|
status = :error
|
|
update_status_queue(row, upload, status)
|
|
end
|
|
|
|
def update_status_queue(row, upload, status)
|
|
status_queue << { id: row[:id], upload_id: upload[:id], status: }
|
|
end
|
|
|
|
def log_status
|
|
error_count_text = error_count > 0 ? "#{error_count} errors".red : "0 errors"
|
|
print "\r%7d / %7d (%s, %s missing)" %
|
|
[current_count, max_count, error_count_text, missing_count]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|