Files
2025-09-29 00:52:08 +02:00

450 lines
17 KiB
Ruby
Executable File

#
# File:: %RS_TOOLSLIB%/pipeline/projectutil/data_convert_file.rb
# Description:: Functions to convert assets.
#
# Author:: David Muir <david.muir@rockstarnorth.com>
# Date:: 6 August 2008
#
#-----------------------------------------------------------------------------
# Uses
#-----------------------------------------------------------------------------
require 'pipeline/config/project'
require 'pipeline/content/content_core'
require 'pipeline/content/treecore'
require 'pipeline/os/path'
require 'pipeline/projectutil/data_content'
require 'pipeline/projectutil/data_convert_map_dependencies'
require 'pipeline/projectutil/data_rpf'
require 'pipeline/projectutil/misc'
require 'pipeline/resourcing/convert'
require 'pipeline/resourcing/path'
require 'pipeline/util/string'
#-----------------------------------------------------------------------------
# Functions
#-----------------------------------------------------------------------------
module Pipeline
module ProjectUtil
#
# == Description
# Conversion exception class.
#
class ConvertException < RuntimeError
attr_reader :filenames
def initialize( message, filenames = [] )
super( message )
@filenames = filenames
end
end
#
# Return a platform file for an independent filename(s). The filenames
# argument can either be a String filename or Array of String filenames.
#
# Returns either an Array of filenames (when multiple files or target is
# nil) or a single filename when a single filename and target is specified.
#
# === Example
# DHM TODO
#
def ProjectUtil::data_convert_platform_filenames( project, branch, filenames, target = nil )
throw ArgumentError.new( "Invalid project specified (#{project.class})." ) \
unless ( project.is_a?( Pipeline::Project ) )
throw ArgumentError.new( "Invalid branch specified (#{branch.class})." ) \
unless ( branch.is_a?( Pipeline::Branch ) )
throw ArgumentError.new( "Invalid target specified (#{target.class})." ) \
if ( ( not target.nil? ) and ( not target.is_a?( Pipeline::Target ) ) )
results = []
if ( filenames.is_a?( String ) ) then
filename = OS::Path::normalise( filenames )
if ( branch.is_export_file?( filename ) or branch.is_processed_file?( filename ) ) then
if ( target.nil? ) then
results = []
branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
target.in_env() do |env|
results << env.subst( Resourcing::convert_independent_filename_to_platform( filename, target ) )
end
end
return ( results )
else
target.in_env() do |env|
return env.subst( Resourcing::convert_independent_filename_to_platform( filename, target ) )
end
end
elsif ( project.is_cache_file?( filename ) )
target.in_env() do |env|
platformFilename = Resourcing::convert_independent_filename_to_platform( OS::Path.get_filename( filename ), target )
return OS::Path.combine( branch.preview, platformFilename )
end
else
throw RuntimeError.new( "Invalid export or processed file: #{filename}." )
end
elsif ( filenames.is_a?( Array ) ) then
filenames.each do |filename|
filename = OS::Path::normalise( filename )
inner = ProjectUtil::data_convert_platform_filenames( project, branch, filename, target )
if ( inner.is_a?( Array ) )
results += inner
else
results << inner
end
end
else
throw ArgumentError.new( "Invalid export or processed filenames object (#{filenames.class})." )
end
return ( results )
end
#
# Convert a file, directory or Array of files and directories from their
# absolute paths only.
#
# The project, branch and hence Ragebuilder version is determined and the
# conversion done.
#
# The filenames passed in must be independent files and from the same project
# and branch.
#
# Returns a Hash with :success and :files symbol keys.
#
# === Example Usage ===
# See %RS_TOOLSLIB%/util/data_convert_file.rb.
#
def ProjectUtil::data_convert_file( filenames, rebuild = false, preview = false, load_content = true, lookup_dependencies = true, &block )
filenames = [ filenames ] unless ( filenames.is_a?( Array ) )
config = Pipeline::Config::instance()
content_group = []
conv_project = config.project
conv_project.load_config( )
conv_branch = conv_project.branches[conv_project.default_branch]
if ( conv_project.nil? ) then
throw RuntimeError::new( 'No project found. Invalid file, configuration or no targets enabled?' + filenames.join(";") )
end
if ( conv_branch.nil? ) then
throw RuntimeError::new( 'No branch found. Invalid file, configuration or no targets enabled?' )
end
# Verify we have one or more platforms enabled; if not display an
# error telling the user nothing will convert.
at_least_one_target = false
conv_branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
at_least_one_target = true
end
if ( ( not at_least_one_target ) and ( not config.user.username.downcase.include?( User::ASSETBUILDER_USER ) ) )
error_msg = "There are no platforms enabled for the current branch.\n"
error_msg += "Project: #{conv_project.uiname}\n"
error_msg += "Branch: #{conv_branch.name}\n\n"
error_msg += "Re-run the installer and enabled one or more platforms."
GUI::MessageBox::error("Platform Conversion Error Notification", error_msg)
return false
end
conv_project.load_content( ) if ( load_content )
content_files_group = Content::Group::new( 'content_files_group' )
elapsed_time = Util::time() do
content_list = conv_project.content.find( ) do |content|
( content.is_a?( Content::File ) )
end
content_files_group.children = content_list
end
# We need to cater for content dependencies
if ( load_content and lookup_dependencies ) then
filenames = ProjectUtil::get_content_with_dependencies( conv_project, filenames )
end
# For each filename we are asking to be converted; find it if it exists
# in the project's content tree, if it exists then pass it down to the
# convert system, otherwise create a Content::File or Content::Directory
# node for it so that it goes through the platform conversion
# (converter_rage).
unique_children = []
filenames.each do |filename|
content_node = nil
has_content = false
if ( load_content ) then
content_node = ProjectUtil::data_content_for_files( conv_project, filename ).shift
if ( content_node.is_a?( Content::Directory ) and preview ) then
content_node.inputs.clear
node = Content::Zip::from_filename_and_target( filename, conv_project.ind_target )
content_node.add_input( node )
end
has_content = ( not content_node.nil? )
end
# DHM FIXME: much of this can be replaced by a call to the newly added:
# data_convert_content_to_platform_content function.
if ( has_content and ( content_node.outputs.size() > 0 ) ) then
# Use content-tree based nodes as inputs to dynamically
# generated target nodes.
content_node.outputs.each do |o|
# This is critical to pass the output nodes down; otherwise
# you don't get the processed nodes being processed.
unique_children << o
conv_branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
content_filename = nil
if( o.is_a?( Content::Directory ) ) then
content_filename = OS::Path::normalise( "#{o.absolute_path}.rpf" )
else
content_filename = o.filename
end
target_filename = ProjectUtil::data_convert_platform_filenames( conv_project, conv_branch, content_filename, target )
target_file = Content::from_filename( conv_project, conv_branch.name, target_filename )
target_file.inputs << o
unique_children << target_file
puts "TARGET [CONTENT]:"
puts "\t#{content_filename}"
puts "\t#{target_file}"
end
end
else
# Fallback as before; generate the platform content node(s)
# and pass to the convert system for platform conversion.
if ( content_node.is_a?( Content::File ) ) then
export_file = Content::from_filename( conv_project, conv_branch.name, filename )
conv_branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
target_filename = ProjectUtil::data_convert_platform_filenames( conv_project, conv_branch, filename, target )
target_file = Content::from_filename( conv_project, conv_branch.name, target_filename )
target_file.inputs << export_file
unique_children << target_file
puts "TARGET [FALLBACK]:"
puts "\t#{target.platform} #{target.target}"
puts "\t#{filename}"
puts "\t#{target_file}"
end
elsif ( content_node.is_a?( Content::Directory ) ) then
conv_branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
fake_filename = OS::Path::normalise( "#{content_node.absolute_path}.rpf" )
target_filename = ProjectUtil::data_convert_platform_filenames( conv_project, conv_branch, fake_filename, target )
target_file = Content::from_filename( conv_project, conv_branch.name, target_filename )
target_file.inputs << content_node
unique_children << target_file
puts "TARGET DIRECTORY [FALLBACK]:"
puts "\t#{target.platform} #{target.target}"
puts "\t#{filename}"
puts "\t#{target_file}"
end
else
# Very old fallback for when there is no content node
# constructed.
export_file = Content::from_filename( conv_project, conv_branch.name, filename )
conv_branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
target_filename = ProjectUtil::data_convert_platform_filenames( conv_project, conv_branch, filename, target )
target_file = Content::from_filename( conv_project, conv_branch.name, target_filename )
target_file.inputs << export_file
unique_children << target_file
puts "TARGET [FALLBACK]:"
puts "\t#{target.platform} #{target.target}"
puts "\t#{filename}"
puts "\t#{target_file}"
end
end
end
end
# Now we simply pass the various content nodes for the passed in files
# down to the ConvertSystem; which handles which converter to pass the
# node to and do its business.
unique_children.uniq!
unique_children.each do |child|
content_group << child
end
converted_files = []
result = true
if ( content_group.size > 0 ) then
converter = Resourcing::ConvertSystem.instance()
converter.setup( conv_project, conv_branch.name, false, rebuild, false, preview, load_content )
result = converter.build( content_group ) do |node, success|
yield( node, success ) if ( block_given? )
if ( node.is_a?( Content::File ) ) then
converted_files << OS::Path::normalise( node.filename )
elsif ( node.is_a?( Content::Directory ) ) then
converted_files << OS::Path::normalise( node.filename )
end
end
else
throw ConvertException::new( "Nothing to convert. Did you specify export files?", filenames )
end
{ :success => result, :files => converted_files }
end
# Enumerates all input_filenames and checks the associated content to see if it has any dependencies
# A merged, distinct array of normalised filenames is returned
def ProjectUtil::get_content_with_dependencies( conv_project, input_filenames )
dependency_filenames = []
#get dependencies for the input_filenames
input_filenames.each do |input_filename|
content_node = ProjectUtil::data_content_for_files( conv_project, input_filename ).shift
if( content_node != nil and (content_node.is_a?( Pipeline::Content::MapZip )) ) then
ProjectUtil::get_lod_dependency_files( content_node, dependency_filenames )
end
end
#combine and remove duplicates
output_filenames = []
input_filenames.each do |input_filename|
output_filenames << OS::Path.normalise(input_filename)
end
dependency_filenames.each do |dependency_filename|
output_filenames << OS::Path.normalise(dependency_filename)
end
output_filenames.uniq!
output_filenames
end
#
# Return Array of content nodes that represent tha platform content-nodes
# for the passed-in content_node (for all enabled platforms).
#
def ProjectUtil::data_convert_content_to_platform_content( project, branch, content_node )
unique_children = []
if ( content_node.outputs.size() > 0 ) then
# Use content-tree based nodes as inputs to dynamically
# generated target nodes.
content_node.outputs.each do |o|
# This is critical to pass the output nodes down; otherwise
# you don't get the processed nodes being processed.
unique_children << o
branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
target_filename = ProjectUtil::data_convert_platform_filenames( project, branch, o.filename, target )
target_file = Content::from_filename( project, branch.name, target_filename )
target_file.inputs << o
unique_children << target_file
end
end
else
# Fallback as before; generate the platform content node(s)
# and pass to the convert system for platform conversion.
if ( content_node.is_a?( Content::Directory ) ) then
branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
fake_filename = OS::Path::normalise( "#{content_node.absolute_path}.rpf" )
target_filename = ProjectUtil::data_convert_platform_filenames( project, branch, fake_filename, target )
target_file = Content::from_filename( project, branch.name, target_filename )
target_file.inputs << content_node
unique_children << target_file
end
elsif ( content_node.is_a?( Content::File ) ) then
filename = content_node.filename
export_file = Content::from_filename( project, branch.name, filename )
branch.targets.each_pair do |platform, target|
next unless ( target.enabled )
target_filename = ProjectUtil::data_convert_platform_filenames( project, branch, filename, target )
target_file = Content::from_filename( project, branch.name, target_filename )
target_file.inputs << export_file
unique_children << target_file
end
else
throw RuntimeError::new( "Invalid content node type (#{content_node.class})." )
end
end
unique_children
end
#
# Convert a ZIP file or Array of ZIP files from their absolute filename only
# to RPF files.
#
# The filenames passed in must be independent files and from the same project
# and branch.
#
# === Example Usage ===
# See %RS_TOOLSLIB%/util/data_convert_zip_to_rpf.rb
#
def ProjectUtil::data_convert_zip_to_rpf( filenames, compressed = false, &block )
filenames = [ filename ] unless ( filenames.is_a?( Array ) )
config = Pipeline::Config::instance()
log = Pipeline::LogSystem::instance().rootlog
conv_project = nil
conv_branch = nil
conv_project, conv_branch = ProjectUtil::get_project_from_filenames( filenames )
outputroot = OS::Path::get_temp_directory()
converted_files = []
filenames.each do |filename|
if ( 0 != 'zip'.casecmp( OS::Path::get_extension( filename ) ) ) then
log.warn( "Skipping non-ZIP file: #{filename}" )
next
end
outputpath = OS::Path::combine( outputroot, OS::Path::get_basename( filename ) )
log.info( "Extracting ZIP: #{filename} to #{outputpath}" )
files = ProjectUtil::data_zip_extract( filename, outputpath, true ) do |packfilename|
log.info( " #{packfilename}" )
end
rpf_filename = OS::Path::replace_ext( filename, 'rpf' )
#---------------------------------------------------------------------
# Package RPF File
#---------------------------------------------------------------------
file_list = []
files.each do |packfilename|
entry = {}
entry[:src] = packfilename
entry[:dst] = packfilename.sub( outputpath+'/', '' )
end
ProjectUtil::data_rpf_create( rpf_filename, files, compressed )
end
converted_files
end
end # ProjectUtil module
end # Pipeline module
# %RS_TOOLSLIB%/pipeline/projectutil/data_convert_file.rb