#!/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