469 lines
15 KiB
Ruby
Executable File
469 lines
15 KiB
Ruby
Executable File
#
|
|
# File:: file_get_usage.rb
|
|
# Description:: Functions for getting file usage.
|
|
#
|
|
# Author:: Marissa Warner-Wu <marissa.warner-wu@rockstarnorth.com>
|
|
# Date:: 5 August 2009
|
|
#
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Uses
|
|
#-----------------------------------------------------------------------------
|
|
require 'pp'
|
|
require 'pipeline/os/file'
|
|
require 'pipeline/resourcing/path'
|
|
require 'pipeline/util/maxscript'
|
|
require "rexml/document"
|
|
include REXML
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Implementation
|
|
#-----------------------------------------------------------------------------
|
|
module Pipeline
|
|
module ProjectUtil
|
|
|
|
#-------------------------------------------------------------------------
|
|
# Functions
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
# == Description
|
|
# A function which determines the usage on MaxScript files in a given directory.
|
|
#
|
|
# 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.
|
|
#
|
|
# g_ToolsRoot = "x:/pipedev/"
|
|
# g_OutputFile = "x:/usage.txt"
|
|
# FileUsageHash::file_get_usage_maxscript( g_ToolsRoot, g_OutputFile )
|
|
#
|
|
def ProjectUtil::file_get_usage_maxscript( toolsroot, outputFile )
|
|
# Generate the usage hash and related warnings
|
|
usage_hash = {}
|
|
bad_refs = {}
|
|
FileUsageHash::create_hash_maxscript( toolsroot ) do |newHash, warnings|
|
|
usage_hash = newhash
|
|
bad_refs = warnings
|
|
end
|
|
|
|
# Generate output
|
|
if outputFile.nil?
|
|
FileUsageHash::pp( usage_hash )
|
|
else
|
|
case OS::Path::get_extension( outputFile )
|
|
when 'txt' then FileUsageHash::to_txt( usage_hash, outputFile, bad_refs )
|
|
when 'xml' then FileUsageHash::to_xml( usage_hash, outputFile )
|
|
else puts "ERROR: This file type is not supported, could not create output file."
|
|
end #case OS::Path::get_extension( outputFile )
|
|
end #if outputFile.nil?
|
|
end #file_get_usage_maxscript
|
|
|
|
|
|
#
|
|
# == Description
|
|
# Similar to file_get_usage_maxscript(), except that it exhaustively attempts to
|
|
# find unused files by checking function and rollout calls.
|
|
#
|
|
# Generates a hash which prints to the screen or to an optional output file, if given
|
|
# (in this case it will only print out the unused items).
|
|
#
|
|
# === Example Usage
|
|
# Pretty much what it says on the box.
|
|
#
|
|
# g_ToolsRoot = "x:/pipedev/"
|
|
# g_OutputFile = "x:/usage.txt"
|
|
# FileUsageHash::file_get_unused_maxscript( g_ToolsRoot, g_OutputFile )
|
|
#
|
|
def ProjectUtil::file_get_unused_maxscript( toolsroot, outputFile )
|
|
# Generate the usage hash and related warnings
|
|
usage_hash = {}
|
|
bad_refs = {}
|
|
puts "Creating the usage hash..."
|
|
FileUsageHash::create_hash_maxscript( toolsroot ) do |newHash, warnings|
|
|
usage_hash = newHash
|
|
bad_refs = warnings
|
|
end
|
|
|
|
# Cull out items by seeing what is really used
|
|
puts "Checking usage against function calls..."
|
|
usage_hash.each do |script, references|
|
|
# Don't check the settings
|
|
next if OS::Path::get_filename( script ) == 'settings.ms'
|
|
|
|
# Start with the usage as false
|
|
used = false
|
|
|
|
scriptpath = Maxscript::full_path( script, toolsroot )
|
|
puts "CHECKING: #{scriptpath}"
|
|
references.each_key do |file|
|
|
# Don't check this file if it's the menu
|
|
next if OS::Path::get_filename( file ) == 'rsutils.mcr'
|
|
|
|
# Don't check global references
|
|
next if file.eql? "global"
|
|
|
|
# Get the usage
|
|
used = Maxscript::file_is_used?( scriptpath, file )
|
|
|
|
# If we couldn't find it then do a global check
|
|
unless used
|
|
partpath = Maxscript::format_path( file )
|
|
if usage_hash.has_key? partpath
|
|
includes = usage_hash[partpath]
|
|
|
|
includes.each_key do |included_file|
|
|
# Don't check global references
|
|
next if included_file.eql? "global"
|
|
|
|
# Otherwise see if it's used
|
|
used = Maxscript::file_is_used?( scriptpath, included_file )
|
|
break if used == true
|
|
end #includes.each
|
|
end #if usage_hash.has_key?
|
|
|
|
# If the file is still unused, mark it
|
|
unless used
|
|
# Create warning
|
|
warning = "Was included in #{file} (line: "
|
|
references[file].each{ |line_number| warning << line_number.to_s << " " }
|
|
warning << ") but no functions or rollouts were called"
|
|
|
|
if bad_refs.has_key? scriptpath
|
|
bad_refs[scriptpath] << warning
|
|
else
|
|
bad_refs[scriptpath] = [warning]
|
|
end
|
|
|
|
# Remove from it from the list of referenced files
|
|
references.delete( file )
|
|
end #unless used
|
|
end #includes.each
|
|
|
|
end #references.each_key
|
|
|
|
# If we still can't find a use for the file, check global function calls
|
|
unless used
|
|
usage_hash.each_key do |file|
|
|
# Don't check the file itself
|
|
next if script.eql? file
|
|
|
|
# Otherwise see if it's used
|
|
filepath = Maxscript::full_path( file, toolsroot )
|
|
used = Maxscript::file_is_used?( scriptpath, filepath )
|
|
break if used == true
|
|
end #usage_hash.each_key
|
|
|
|
# Add a global reference
|
|
references['global'] = [0] if used
|
|
end #unless used
|
|
end #usage_hash.each
|
|
|
|
# Generate output
|
|
if outputFile.nil?
|
|
FileUsageHash::pp( usage_hash )
|
|
else
|
|
puts "Creating output file..."
|
|
case OS::Path::get_extension( outputFile )
|
|
when 'txt' then FileUsageHash::to_txt_unused( usage_hash, outputFile, bad_refs )
|
|
when 'xml' then FileUsageHash::to_xml_unused( usage_hash, outputFile )
|
|
else puts "ERROR: This file type is not supported, could not create output file."
|
|
end #case OS::Path::get_extension( outputFile )
|
|
end #if outputFile.nil?
|
|
end #file_get_usage_maxscript
|
|
|
|
end # ProjectUtil module
|
|
|
|
|
|
#
|
|
# == Description
|
|
# Small class for functions which create and manipulate usage hashes for sets of files.
|
|
# The hash comes in the following form:
|
|
#
|
|
#
|
|
class FileUsageHash
|
|
|
|
#---------------------------------------------------------------------
|
|
# Class Methods
|
|
#---------------------------------------------------------------------
|
|
|
|
#
|
|
# == Description
|
|
# A function which determines the usage on MaxScript files in a given directory.
|
|
# Yields the hash and a hash of warnings to an optional given block.
|
|
#
|
|
# === Example Usage
|
|
# Pretty much what it says on the box.
|
|
#
|
|
# g_ToolsRoot = "x:/pipedev/"
|
|
# FileUsageHash::create_hash_maxscript( g_ToolsRoot )
|
|
#
|
|
def FileUsageHash::create_hash_maxscript( toolsroot, &block )
|
|
# Get all the maxscript files
|
|
ms_files = Maxscript::find_files( toolsroot )
|
|
|
|
# Create the hash
|
|
file_hash = {}
|
|
ms_files.each do |filepath|
|
|
# Add to the hash unless this is a startup script, which we can safely skip
|
|
part_path = Maxscript::format_path( filepath )
|
|
file_hash[part_path] = {} unless OS::Path::get_trailing_directory( part_path ) == "startup"
|
|
end
|
|
|
|
# Add the menus to the file list
|
|
rsutils = OS::Path::combine( toolsroot, Maxscript::dir_max, "ui/macroscripts/rsutils.mcr" )
|
|
ms_files << rsutils
|
|
|
|
# Keep track of bad references
|
|
bad_refs = {}
|
|
|
|
# Search through the files
|
|
ms_files.each do |scriptfile|
|
|
puts "USAGE: #{scriptfile}"
|
|
|
|
# Get the contents of this file
|
|
text = Maxscript::get_lines( scriptfile )
|
|
|
|
# Parse each line of text
|
|
text.each_index do |index|
|
|
line = text[index]
|
|
line_number = index + 1
|
|
|
|
# Try to get the filename
|
|
filename = Maxscript::get_included_file( line, scriptfile )
|
|
|
|
unless filename.empty?
|
|
# Try to find this file in the hash
|
|
if file_hash.has_key?(filename)
|
|
# Add this script file to the list of places this file was used
|
|
refs = file_hash[filename]
|
|
if refs.has_key?(scriptfile)
|
|
refs[scriptfile] << line_number
|
|
else
|
|
refs[scriptfile] = [line_number]
|
|
end
|
|
else
|
|
# Store a warning if the file wasn't found unless this is a comment
|
|
unless Maxscript::line_is_comment?( line )
|
|
warning = "#{filename} in the following line: \"#{line.chomp}\""
|
|
if bad_refs.has_key? scriptfile
|
|
bad_refs[scriptfile] << warning
|
|
else
|
|
bad_refs[scriptfile] = [warning]
|
|
end
|
|
end #unless Maxscript::line_is_comment?
|
|
end #if file_hash.has_key?
|
|
end #unless filename.empty?
|
|
|
|
end #text.each
|
|
end #ms_files.each do |scriptfile|
|
|
|
|
yield( file_hash, bad_refs ) if block_given?
|
|
end #create_hash_maxscript
|
|
|
|
|
|
#
|
|
# == 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 FileUsageHash::pp( usage_hash )
|
|
usage_hash.each do |file, references|
|
|
puts "---------------- #{file}:"
|
|
pp references
|
|
end
|
|
end #pp
|
|
|
|
|
|
#
|
|
# == Description
|
|
# A specialised helper function which prints the Get Usage hash information to a .txt
|
|
# file. If given a hash of bad references it will also format these and print out
|
|
# the information at the end of the file.
|
|
#
|
|
# === Example Usage
|
|
# MWW TODO
|
|
#
|
|
def FileUsageHash::to_txt( usage_hash, outputFile, bad_refs={} )
|
|
::FileUtils::rm( outputFile ) if ( File.exist?( outputFile ) )
|
|
log = File.new(outputFile, 'w')
|
|
log.write("=== MAXSCRIPT FILE USAGE ===\n\n")
|
|
|
|
# Print out information for each item in the hash
|
|
keys = usage_hash.keys
|
|
keys.sort!
|
|
keys.each do |script_name|
|
|
usage_info = usage_hash[script_name]
|
|
log.write("----#{script_name}:\n")
|
|
if usage_info.empty?
|
|
log.write("[[UNUSED]]\n\n")
|
|
else
|
|
usage_info.each do |file, lines|
|
|
log.write("\t\t#{file} used this at line(s): ")
|
|
lines.each { |number| log.write( "#{number.to_s} " ) }
|
|
log.write("\n")
|
|
end #usage_info.each
|
|
|
|
log.write("\n")
|
|
end
|
|
end #file_hash.each
|
|
|
|
# Print out bad refs warning
|
|
unless bad_refs.empty?
|
|
log.write("============= Found the following possible bad refs:\n")
|
|
bad_refs.each do |file_name, warnings|
|
|
log.write("----#{file_name}:\n")
|
|
warnings.each { |ref| log.write("\t\t#{ref}\n") }
|
|
log.write("\n")
|
|
end #bad_refs.each
|
|
end #unless bad_refs.empty?
|
|
|
|
log.close()
|
|
puts "Wrote output file to #{outputFile}."
|
|
end #to_txt
|
|
|
|
|
|
#
|
|
# == Description
|
|
# The same as to_txt(), but only prints out information for unused files. If given
|
|
# a hash of bad references it will also format these and print out the information
|
|
# at the end of the file.
|
|
#
|
|
# === Example Usage
|
|
# MWW TODO
|
|
#
|
|
def FileUsageHash::to_txt_unused( usage_hash, outputFile, bad_refs={} )
|
|
::FileUtils::rm( outputFile ) if ( File.exist?( outputFile ) )
|
|
log = File.new(outputFile, 'w')
|
|
log.write("=== MAXSCRIPT FILE USAGE -- UNUSED ===\n\n")
|
|
|
|
# Print out information for each item in the hash
|
|
keys = usage_hash.keys
|
|
keys.sort!
|
|
keys.each do |script_name|
|
|
usage_info = usage_hash[script_name]
|
|
log.write("#{script_name}\n") if usage_info.empty?
|
|
end #usage_hash.each
|
|
|
|
log.write("\n")
|
|
|
|
# Print out bad refs warning
|
|
unless bad_refs.empty?
|
|
log.write("============= Found the following possible bad refs:\n")
|
|
bad_refs.each do |file_name, warnings|
|
|
log.write("----#{file_name}:\n")
|
|
warnings.each { |ref| log.write("\t\t#{ref}\n") }
|
|
log.write("\n")
|
|
end #bad_refs.each
|
|
end #unless bad_refs.empty?
|
|
|
|
log.close()
|
|
puts "Wrote output file to #{outputFile}"
|
|
end #to_txt_unused
|
|
|
|
|
|
#
|
|
# == Description
|
|
# A specialised helper function which prints the Get Usage hash information to a .xml
|
|
# file. If no output file is given then it passes back the REXML Document object.
|
|
#
|
|
# Note that this function does not take or print any of the bad reference warnings.
|
|
# To print this information, use to_txt() or to_txt_unused().
|
|
#
|
|
# === Example Usage
|
|
# MWW TODO
|
|
#
|
|
def FileUsageHash::to_xml( usage_hash, outputFile )
|
|
::FileUtils::rm( outputFile ) if ( File.exist?( outputFile ) )
|
|
|
|
# Create document
|
|
log = Document.new
|
|
log << XMLDecl.new
|
|
log << Comment.new( "MAXSCRIPT FILE USAGE" )
|
|
root = Element.new( 'Usage' )
|
|
|
|
# Create elements for each file
|
|
keys = usage_hash.keys
|
|
keys.sort!
|
|
keys.each do |file|
|
|
references = usage_hash[file]
|
|
file_elem = root.add_element( 'file' )
|
|
file_elem.add_attribute( 'name', file )
|
|
|
|
references.each do |ref_file, lines|
|
|
ref_elem = file_elem.add_element( 'ref_file' )
|
|
ref_elem.add_attribute( 'name', ref_file )
|
|
lines.each do |number|
|
|
line_elem = ref_elem.add_element( 'line' )
|
|
line_elem.add_text( number.to_s )
|
|
end
|
|
end #references.each
|
|
end #usage_hash.each
|
|
|
|
log << root
|
|
|
|
# Write the XML or pass back the document
|
|
if outputFile.nil?
|
|
return log
|
|
else
|
|
File.open( outputFile, 'w' ) do |file|
|
|
fmt = REXML::Formatters::Pretty.new()
|
|
fmt.write( log, file )
|
|
end
|
|
end #if outputFile.nil?
|
|
end #to_xml
|
|
|
|
|
|
#
|
|
# == Description
|
|
# The same as to_xml(), but only prints out information for unused items. If no output
|
|
# file is given then it passes back the REXML Document object.
|
|
#
|
|
# Note that this function does not take or print any of the bad reference warnings.
|
|
# To print this information, use to_txt() or to_txt_unused().
|
|
#
|
|
# === Example Usage
|
|
# MWW TODO
|
|
#
|
|
def FileUsageHash::to_xml_unused( usage_hash, outputFile )
|
|
::FileUtils::rm( outputFile ) if ( File.exist?( outputFile ) )
|
|
|
|
# Create document
|
|
log = Document.new
|
|
log << XMLDecl.new
|
|
log << Comment.new( "MAXSCRIPT FILE USAGE -- UNUSED" )
|
|
root = Element.new( 'Usage' )
|
|
|
|
# Create elements for each file
|
|
keys = usage_hash.keys
|
|
keys.sort!
|
|
keys.each do |file|
|
|
references = usage_hash[file]
|
|
if references.empty?
|
|
file_elem = root.add_element( 'file' )
|
|
file_elem.add_attribute( 'name', file )
|
|
end
|
|
end #usage_hash.each
|
|
|
|
log << root
|
|
|
|
# Write the XML or pass back the document
|
|
if outputFile.nil?
|
|
return log
|
|
else
|
|
File.open( outputFile, 'w' ) do |file|
|
|
fmt = REXML::Formatters::Pretty.new()
|
|
fmt.write( log, file )
|
|
end
|
|
end #if outputFile.nil?
|
|
end #to_xml_unused
|
|
|
|
end #FileUsageHash
|
|
|
|
end # Pipeline module
|
|
|
|
# file_get_usage.rb |