# # File:: data_get_usage.rb # Description:: Functions for getting the usage of items in a given file. # # Author:: Marissa Warner-Wu # Date:: 22 July 2009 # #----------------------------------------------------------------------------- # Uses #----------------------------------------------------------------------------- require 'pp' require 'pipeline/os/file' require 'pipeline/resourcing/path' require 'pipeline/projectutil/data_search' require 'pipeline/projectutil/data_extract' require "rexml/document" include REXML #----------------------------------------------------------------------------- # Implementation #----------------------------------------------------------------------------- module Pipeline module ProjectUtil #------------------------------------------------------------------------- # Functions #------------------------------------------------------------------------- # # == Description # A function for projects with levels which iterates through the objects in a given IDE file and # then searches for them in the IPLs using data_get_usage_IPL(). # # Generates a hash which prints to the screen or to an optional output file, if given. # # === Example Usage # Pretty much what it says on the box. # # ProjectUtil::data_get_usage_IDE( g_Project, g_TargetName, g_OutputFile, g_IDE ) # def ProjectUtil::data_get_usage_IDE( project, target, outputFile, ide ) throw ArgumentError.new( "IDE file does not exist (#{ide})." ) unless File.exist?( ide ) # Set the level, if needed level = "" if true #project.has_levels if( OS::Path::get_trailing_directory(ide) == "generic" ) level = "generic" puts "This map has been determined as being generic.\n\n" else level = OS::Path::get_directories(ide)[-2] throw ParseError.new( "Unable to get level name from IDE path." ) if level.empty? puts "This map has been determined as being part of the #{level} level.\n\n" end end #project.has_levels # Get the list of files to search files = [] if level.empty? throw RuntimeError.new( "Currently no support for non-leveled projects." ) else files = ProjectUtil::data_find_maps_levels(project, level) end # Parse the IDE for objects objects = [] File.open(ide, 'r') do text = IO.readlines( ide ) start = text.index( "objs\n" ) + 1 finish = text.index( "end\n" ) - 1 objects = text[start..finish] throw ParseError.new( "Unable to parse the IDE." ) if objects.empty? end # Print objects and set up the hash objects_hash = {} objects.each do |line| # Parse each line in the list for the object name item = line.split(',')[0].downcase # Add item to the hash, values are currently empty arrays objects_hash[item] = {} end #objects.each # Search the IPLs ProjectUtil::data_get_usage_IPL(project, files, objects_hash) do |output_hash| if outputFile.empty? # If we have no output file, pretty print to the screen ObjectUsageHash::pp( output_hash ) else # Otherwise, write to the output file puts "\nWriting output to #{outputFile}" if OS::Path::get_extension( outputFile ) == "xml" ObjectUsageHash::to_xml( outputFile, OS::Path::get_basename(ide), output_hash) else # Currently we are using ObjectUsageHash::to_txt_by_map(), but we could also use # ObjectUsageHash::to_txt_by_ipl() for more detailed output. ObjectUsageHash::to_txt_by_map( outputFile, OS::Path::get_basename(ide), output_hash) end end end #data_get_usage_IPL end #data_get_usage_IDE # # == Description # A function which takes a hash with object names as keys and a list of files and searches # the IPLs in those files for the given objects. The value for each key is given as another # hash which gives the object count by map name. The hash then looks like this: # # { item name => { map name => [[ipl name1, count], [ipl name2, count]] } } # # Checks both static and streaming IPLs. Yields the updated hash to an optional given block or # pretty prints to the screen. # # === Example Usage # Suppose that the item "tools_test" appears 10 times in alp_lake.ipl. We # should then get the following from this piece of code: # # require 'pp' # file_list = ["X:\jimmy\build\dev\independent\levels\alpine\alp_lake.ipl"] # items = { "tools_test" => [] } # ProjectUtil::data_search_IPL(project, file_list, objects_hash) do |myHash| # pp myHash # end # ==> {"tools_test" => {["alp_lake" => [["alp_lake", 10]] } } # # Getting info from the hash: # all_map_info = myHash["tools_test"] # map_info = all_map_info["alp_lake"] # ipl_info = map_info.assoc("alp_lake") # ipl_name = ipl_info[0] # count = ipl_info[1] # def ProjectUtil::data_get_usage_IPL(project, files, objects, &block) # Set variables for extracting img/rpf files temp = "X:/temp" ::FileUtils::rm_r( temp ) if ( ::File::directory?( temp ) ) r = RageUtils.new( project, project.default_branch ) # Go through the list of IPLs puts "Checking the following IPLs..." files.each do |file| # Switch by file extension case OS::Path::get_extension( file ) when "ipl" puts OS::Path::get_filename( file ) ipl_objects = ProjectUtil::data_search_object_in_IPL(file, objects) objects = ObjectUsageHash::merge(objects, ipl_objects) when "img" ProjectUtil::data_extract_image( r, file, temp ) do |extracted_filename| if (OS::Path::get_extension( extracted_filename ) == "ipl") puts OS::Path::get_filename( extracted_filename ) ipl_objects = ProjectUtil::data_search_object_in_IPL(extracted_filename, objects) objects = ObjectUsageHash::merge(objects, ipl_objects) end end #data_extract_image ::FileUtils::rm_r( temp ) if ( ::File::directory?( temp ) ) when "rpf" ProjectUtil::data_extract_rpf( r, file, temp ) do |extracted_filename| if (OS::Path::get_extension( extracted_filename ) == "ipl") puts OS::Path::get_filename( extracted_filename ) ipl_objects = ProjectUtil::data_search_object_in_IPL(extracted_filename, objects) objects = ObjectUsageHash::merge(objects, ipl_objects) end end #data_extract_rpf ::FileUtils::rm_r( temp ) if ::File::directory?( temp ) end #case OS::Path::get_extension( file ) end #files.each # If a block is given then yield the object hash, otherwise pretty print it if block_given? yield( objects ) else ObjectUsageHash::pp( objects ) end end #data_get_usage_IPL end # ProjectUtil module # # == Description # Small class for helper functions which work with the hash object used in data_get_usage_IPL(). # class ObjectUsageHash #--------------------------------------------------------------------- # Class Methods #--------------------------------------------------------------------- # # == Description # A specialised helper function which merges the hash objects used in data_get_usage_IPL(). # Returns the merged hash. # # === Example Usage # Assumes that the parent hash is one like that received by data_get_usage_IPL(), which contains # information for all the maps, and the child hash is one like that generated by data_search_object_in_IPL() # which contains only information for a single IPL. # def ObjectUsageHash::merge(parent_hash, child_hash) # Create the new hash for merging temp_hash = Hash.new new_hash = Hash.new # Go through the child hash child_hash.each do |key, value| # Pull out the map name map_name = "" if value[0].include?( "_stream" ) map_name = value[0].split( "_stream" )[0] else map_name = value[0] end # Update map info map_info = parent_hash[key] if map_info.has_key?( map_name ) # If we already have info for this map, add to the existing info map_info[map_name] << value else # Otherwise create new info map_info[map_name] = [value] end # Construct the new value temp_hash[key] = map_info end #child_hash.each do # Merge the new values with the parent parent_hash.each_key do |key| if temp_hash.has_key?( key ) new_hash[key] = temp_hash[key] else new_hash[key] = parent_hash[key] end end #Return the merged hash new_hash end #merge # # == Description # A specialised helper function which pretty prints the Get Usage hash information. # # === Example Usage # Fairly self-explanatory, only really useful for debugging. Usually you would want # to print to a file as in below. # # def ObjectUsageHash::pp( usage_hash ) usage_hash.each do |item, mapInfo| puts "---------------- #{item}:" pp mapInfo end end #pp # # == Description # A specialised helper function which prints out the Get Usage hash information # to a text file. # # Only prints info by IPL and not by map name. # # === Example Usage # Suppose tools_test is an object in the map alp_test. # # output_file = "x:/test.txt" # map_file = "alp_test" # myHash = {"tools_test" => {["alp_lake" => [["alp_lake", 10]] } } # ObjectUsageHash::to_txt_by_ipl(output_file, map_file, myHash) # # This would give you a file x:/test.txt which contains the following: # """ # --- Object usage for alp_test --- # # --- tools_test: # alp_lake - 10 # """ # # def ObjectUsageHash::to_txt_by_ipl( outputFile, mapFile, usage_hash ) throw ArgumentError.new("No output file given.") if (outputFile.nil? or outputFile.empty?) # Open the output file and start writing ::FileUtils::rm( outputFile ) if ( File.exist?( outputFile ) ) log = File.new( outputFile, 'w' ) log.write( "--- Object usage information for #{mapFile} ---\n\n" ) # Alphabetise the output key_list = usage_hash.keys key_list.sort! # Print info for each item key_list.each do |item| # Write the item name log.write("--- #{item}:\n") # Write the map info mapInfo = usage_hash[item] if mapInfo.empty? log.write("[[UNUSED]]\n") else mapInfo.each_value do |ipls| ipls.each { |iplInfo| log.write("#{iplInfo[0]} - #{iplInfo[1]}\n") } end end #if mapInfo.empty? log.write("\n") end #usage_hash.each log.close() end #to_txt_by_ipl # # == Description # A specialised helper function which prints out the Get Usage hash information # to a text file. # # Only prints info by map name and not by IPL. # # === Example Usage # Suppose tools_test is an object in the map alp_test. # # output_file = "x:/test.txt" # map_file = "alp_test" # myHash = {"tools_test" => {["alp_lake" => [["alp_lake", 10]] } } # ObjectUsageHash::to_txt_by_map(output_file, map_file, myHash) # # This would give you a file x:/test.txt which contains the following: # """ # --- Object usage for alp_test --- # # --- tools_test: # alp_lake - 10 # """ # # def ObjectUsageHash::to_txt_by_map( outputFile, mapFile, usage_hash ) throw ArgumentError.new("No output file given.") if (outputFile.nil? or outputFile.empty?) # Open the output file and start writing ::FileUtils::rm( outputFile ) if ( File.exist?( outputFile ) ) log = File.new( outputFile, 'w' ) log.write( "--- Object usage information for #{mapFile} ---\n\n" ) # Alphabetise the output key_list = usage_hash.keys key_list.sort! # Print info for each item key_list.each do |item| # Write the item name log.write("--- #{item}:\n") # Write the map info mapInfo = usage_hash[item] if mapInfo.empty? log.write("[[UNUSED]]\n") else mapInfo.each do |map, ipls| count = 0 ipls.each { |iplInfo| count += iplInfo[1] } log.write("#{map} - #{count}\n") end end #if mapInfo.empty? log.write("\n") end #usage_hash.each log.close() end #to_txt_by_map # # == Description # A specialised helper function which prints out the Get Usage hash information # to an XML file. # # === Example Usage # Suppose tools_test is an object in the map alp_test. # # output_file = "x:/test.xml" # map_file = "alp_test" # myHash = {"tools_test" => {["alp_lake" => [["alp_lake", 10]] } } # ObjectUsageHash::to_xml(output_file, map_file, myHash) # # This would give you a file x:/test.xml which contains the following content: # """ # # # # # # # """ # # def ObjectUsageHash::to_xml( outputFile, mapFile, usage_hash ) throw ArgumentError.new("No output file given.") if (outputFile.nil? or outputFile.empty?) # Open the output file and start writing ::FileUtils::rm( outputFile ) if ( File.exist?( outputFile ) ) log = Document.new log << XMLDecl.new log << Comment.new("Object usage information for #{mapFile}") # Print props file name root = Element.new( 'props' ) root.add_attribute( 'name', mapFile ) # Alphabetise the output key_list = usage_hash.keys key_list.sort! # Print info for each item key_list.each do |item| # Write the item name item_elem = root.add_element( 'item' ) item_elem.add_attribute( 'name', item ) # Write the map info mapInfo = usage_hash[item] unless mapInfo.empty? mapInfo.each do |map, ipls| map_elem = item_elem.add_element( 'map' ) map_elem.add_attribute( 'name', map ) ipls.each do |iplInfo| ipl_elem = map_elem.add_element( 'ipl' ) ipl_elem.add_attribute( 'name', iplInfo[0] ) ipl_elem.add_attribute( 'count', iplInfo[1].to_s ) end end #mapInfo.each end #if mapInfo.empty? end #usage_hash.each log << root # Write the XML File.open( outputFile, 'w' ) do |file| fmt = REXML::Formatters::Pretty.new() fmt.write( log, file ) end end #to_xml end #ObjectUsageHash class end # Pipeline module # data_get_usage.rb