450 lines
17 KiB
Ruby
Executable File
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
|