#!/usr/bin/ruby # = Synopsis # # treemapDataGen: builds JSON formatted data for javascript treemap visualizer # = Usage # # treemapDataGen [ -p port ] [ -u user ] [ -a areaDataType ] [ -s shadingDataType ] # # Allowed data types: # filesize - sum of file sizes per directory, in bytes # filecount - file count per directory # changecount - number of changes per directory $:.unshift File.join( File.dirname( $0 ), "p4ruby", RUBY_PLATFORM ) $:.unshift "/Library/Ruby/Gems/1.8/gems/json-1.1.3/lib/" load File.join( File.dirname( $0 ), "treemapCoreData.rb" ) require 'P4' require 'json' require 'getoptlong' require 'rdoc/usage' def getNodeData( path, areaType, shadingType ) sizes = 0 changes = 0 # grab all the data we need first if( areaType == "filesize" || areaType == "filecount" || shadingType == "filesize" || shadingType == "filecount" ) sizes = $p4.run_sizes( "-s", path ) end if( areaType == "changecount" || shadingType == "changecount" ) changes = $p4.run_changes( path ) end if( areaType == "fixcount" || shadingType == "fixcount" ) fixes = $p4.run_fixes( path ) end data = Array.new() case areaType when "filesize" data.push( { "key" => "size", "value" => [ 1, (sizes[0]["fileSize"]).to_i() ].max } ) when "filecount" data.push( { "key" => "size", "value" => (sizes[0]["fileCount"]).to_i() } ) when "changecount" data.push( { "key" => "size", "value" => (changes.length) } ) when "fixcount" data.push( { "key" => "size", "value" => (fixes.length) } ) end case shadingType when "filesize" data.push( { "key" => "count", "value" => [ 1, (sizes[0]["fileSize"]).to_i() ].max } ) when "filecount" data.push( { "key" => "count", "value" => (sizes[0]["fileCount"]).to_i() } ) when "changecount" data.push( { "key" => "count", "value" => (changes.length) } ) when "fixcount" data.push( { "key" => "count", "value" => (fixes.length) } ) end if( data[0]["value"] > $areaMax ) $areaMax = data[0]["value"] end if( data[1]["value"] > $shadingMax ) $shadingMax = data[1]["value"] end return data end def getSumChildData( path, childer, areaType, shadingType ) count = size = 0 childer.each do |c| c["data"].each do |d| if( d["key"] == "size" ) size += d["value"] end if( d["key"] == "count" ) count += d["value"] end end end # ignore the summed data if we are dealing with objects that don't sum up well if( areaType == "changecount" || shadingType == "changecount" ) changes = $p4.run_changes( path ) if( areaType == "changecount" ) size = changes.length; end if( shadingType == "changecount" ) count = changes.length; end end if( areaType == "fixcount" || shadingType == "fixcount" ) fixes = $p4.run_fixes( path ) if( areaType == "fixcount" ) size = fixes.length; end if( shadingType == "fixcount" ) count = fixes.length; end end # set values for count and size return [ { "key" => "size", "value" => size }, { "key" => "count", "value" => count } ] end def buildTreeData( dir, path, depth, areaType, shadingType ) tn = { "id" => path, "name" => dir } if( depth == $maxDepth ) # get node data for this leaf tn["data"] = getNodeData( path + "/...", areaType, shadingType ) tn["children"] = [] return tn end # run p4 dirs # call build tree data on all of the paths returned by dirs # stick results into an array dirArray = Array.new dirs = $p4.run_dirs( path + "/*" ) dirs.each do |dir| paths = dir["dir"].split( '/' ) dirArray.push( buildTreeData( paths[ paths.length - 1 ], dir["dir"], depth + 1, areaType, shadingType ) ) end # get local file data size and create faux "child" files = { "id" => path + "/localFiles", "name" => "localFiles", "children" => [] } files["data"] = getNodeData( path + "/*", areaType, shadingType ) if( (files["data"][1]["value"]).to_i() != 0 ) dirArray.push( files ) end tn["data"] = getSumChildData( path + "/...", dirArray, areaType, shadingType ) tn["children"] = dirArray # return a hash return tn end # # main # begin # unreasonable defaults port = "play:5432" user = "matt" areaType = "filesize" shadingType = "filecount" # a global value because I am lazy $maxDepth = 4 $areaMax = 0 $shadingMax = 0 # get the command line options if any, overriding the defaults opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--user', '-u', GetoptLong::REQUIRED_ARGUMENT ], [ '--port', '-p', GetoptLong::REQUIRED_ARGUMENT ], [ '--area', '-a', GetoptLong::REQUIRED_ARGUMENT ], [ '--shading', '-s', GetoptLong::REQUIRED_ARGUMENT ], [ '--depth', '-d', GetoptLong::REQUIRED_ARGUMENT ] ) opts.each do |opt, arg| case opt when '--help' RDoc::usage when '--user' user = arg when '--port' port = arg when '--depth' $maxDepth = arg.to_i() when '--area' areaType = arg when '--shading' shadingType = arg end end if( !isValidType( shadingType ) ) puts "Invalid shading type. Check 'treemapDataGen -h' for valid types" return end if( !isValidType( areaType ) ) puts "Invalid area type. Check 'treemapDataGen -h' for valid types." return end # time to build the "tree" $p4 = P4.new() $p4.prog = "p4treeDataGen" $p4.port = port $p4.user = user $p4.connect() ds = $p4.run_depots() depots = Array.new() ds.each do |d| if( d["type"] != "local" && d["type"] != "stream" ) next end dirArray = Array.new(); dirs = $p4.run_dirs( "//" + d["name"] + "/*" ) dirs.each do |dir| paths = dir["dir"].split( '/' ) dirArray.push( buildTreeData( paths[ paths.length - 1 ], dir["dir"], 1, areaType, shadingType ) ) end depot = { "id" => "//" + d["name"], "name" => d["name"] } depot["data"] = getSumChildData( "//" + d["name"] + "/...", dirArray, areaType, shadingType ) depot["children"] = dirArray; # verify there is something in the depot if( (depot["data"][0]["value"]).to_i() != 0 && (depot["data"][1]["value"]).to_i() != 0) depots.push( depot ) end end # build our root node server = {} server["id"] = port server["name"] = port server["children"] = depots server["data"] = getSumChildData( "//...", depots, areaType, shadingType ) # write the data out basename = port.delete( ':' ) + "-" + areaType + "-" + shadingType Dir.chdir( "sdata" ) output = File.new( basename + ".json", "w" ) output.puts JSON.pretty_generate( server ) output.close #write the data about the data out data = {} data["server"] = port data["areaType"] = getPrettyType( areaType ) data["shadingType"] = getPrettyType( shadingType ) data["areaMax"] = $areaMax data["shadingMax"] = $shadingMax data["tooltipText"] = Array.new( ) data["tooltipText"].push( getPrettyType( areaType ) ) data["tooltipText"].push( getPrettyType( shadingType ) ) output = File.new( basename + ".dat", "w" ) output.puts JSON.pretty_generate( data ) output.close end