mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: Import and export themes in a .tar.gz format (#6916)
This commit is contained in:
@@ -2,7 +2,6 @@ module ThemeStore; end
|
||||
|
||||
class ThemeStore::GitImporter
|
||||
|
||||
class ImportFailed < StandardError; end
|
||||
attr_reader :url
|
||||
|
||||
def initialize(url, private_key: nil, branch: nil)
|
||||
@@ -58,6 +57,12 @@ class ThemeStore::GitImporter
|
||||
end
|
||||
end
|
||||
|
||||
def all_files
|
||||
Dir.chdir(@temp_folder) do
|
||||
Dir.glob("**/*").reject { |f| File.directory?(f) }
|
||||
end
|
||||
end
|
||||
|
||||
def [](value)
|
||||
fullpath = real_path(value)
|
||||
return nil unless fullpath
|
||||
@@ -73,8 +78,8 @@ class ThemeStore::GitImporter
|
||||
else
|
||||
Discourse::Utils.execute_command("git", "clone", @url, @temp_folder)
|
||||
end
|
||||
rescue => err
|
||||
raise ImportFailed.new(err.message)
|
||||
rescue RuntimeError => err
|
||||
raise RemoteTheme::ImportError.new(I18n.t("themes.import_error.git"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -94,8 +99,8 @@ class ThemeStore::GitImporter
|
||||
else
|
||||
Discourse::Utils.execute_command(git_ssh_command, "git", "clone", @url, @temp_folder)
|
||||
end
|
||||
rescue => err
|
||||
raise ImportFailed.new(err.message)
|
||||
rescue RuntimeError => err
|
||||
raise RemoteTheme::ImportError.new(I18n.t("themes.import_error.git"))
|
||||
end
|
||||
ensure
|
||||
FileUtils.rm_rf ssh_folder
|
||||
|
62
lib/theme_store/tgz_exporter.rb
Normal file
62
lib/theme_store/tgz_exporter.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
module ThemeStore; end
|
||||
|
||||
class ThemeStore::TgzExporter
|
||||
|
||||
def initialize(theme)
|
||||
@theme = theme
|
||||
@temp_folder = "#{Pathname.new(Dir.tmpdir).realpath}/discourse_theme_#{SecureRandom.hex}"
|
||||
@export_name = "discourse-#{@theme.name.downcase.gsub(/[^0-9a-z.\-]/, '-')}-theme"
|
||||
end
|
||||
|
||||
def package_filename
|
||||
export_package
|
||||
end
|
||||
|
||||
def cleanup!
|
||||
FileUtils.rm_rf(@temp_folder)
|
||||
end
|
||||
|
||||
private
|
||||
def export_to_folder
|
||||
FileUtils.mkdir(@temp_folder)
|
||||
|
||||
Dir.chdir(@temp_folder) do
|
||||
FileUtils.mkdir(@export_name)
|
||||
|
||||
@theme.theme_fields.each do |field|
|
||||
next unless path = field.file_path
|
||||
|
||||
# Belt and braces approach here. All the user input should already be
|
||||
# sanitized, but check for attempts to leave the temp directory anyway
|
||||
pathname = Pathname.new("#{@export_name}/#{path}")
|
||||
folder_path = pathname.parent.realdirpath
|
||||
raise RuntimeError.new("Theme exporter tried to leave directory") unless folder_path.to_s.starts_with?("#{@temp_folder}/#{@export_name}")
|
||||
folder_path.mkpath
|
||||
path = pathname.realdirpath
|
||||
raise RuntimeError.new("Theme exporter tried to leave directory") unless path.to_s.starts_with?("#{@temp_folder}/#{@export_name}")
|
||||
|
||||
if ThemeField.types[field.type_id] == :theme_upload_var
|
||||
filename = Discourse.store.path_for(field.upload)
|
||||
content = filename ? File.read(filename) : Discourse.store.download(object.upload).read
|
||||
else
|
||||
content = field.value
|
||||
end
|
||||
File.write(path, content)
|
||||
end
|
||||
|
||||
File.write("#{@export_name}/about.json", JSON.pretty_generate(@theme.generate_metadata_hash))
|
||||
end
|
||||
@temp_folder
|
||||
end
|
||||
|
||||
def export_package
|
||||
export_to_folder
|
||||
Dir.chdir(@temp_folder) do
|
||||
tar_filename = "#{@export_name}.tar"
|
||||
Discourse::Utils.execute_command('tar', '--create', '--file', tar_filename, @export_name, failure_message: "Failed to tar theme.")
|
||||
Discourse::Utils.execute_command('gzip', '-5', tar_filename, failure_message: "Failed to gzip archive.")
|
||||
"#{@temp_folder}/#{tar_filename}.gz"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@@ -14,6 +14,8 @@ class ThemeStore::TgzImporter
|
||||
Dir.chdir(@temp_folder) do
|
||||
Discourse::Utils.execute_command("tar", "-xzvf", @filename, "--strip", "1")
|
||||
end
|
||||
rescue RuntimeError
|
||||
raise RemoteTheme::ImportError, I18n.t("themes.import_error.unpack_failed")
|
||||
end
|
||||
|
||||
def cleanup!
|
||||
@@ -38,6 +40,12 @@ class ThemeStore::TgzImporter
|
||||
end
|
||||
end
|
||||
|
||||
def all_files
|
||||
Dir.chdir(@temp_folder) do
|
||||
Dir.glob("**/*").reject { |f| File.directory?(f) }
|
||||
end
|
||||
end
|
||||
|
||||
def [](value)
|
||||
fullpath = real_path(value)
|
||||
return nil unless fullpath
|
||||
|
Reference in New Issue
Block a user