blob: dbc8402b32f096bfc14f5e9df721b449d9dafbeb [file] [log] [blame]
#!/usr/bin/perl -w
# Copyright (C) 2008 Apple Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use strict;
use File::Basename;
sub printDependencyTree($);
my $basename = basename($0);
@ARGV or die "Usage: $basename sln1 [sln2 sln3...]";
foreach my $sln (@ARGV) {
printDependencyTree($sln);
}
exit;
sub printDependencyTree($)
{
my ($sln) = @_;
unless (-f $sln) {
warn "Warning: Can't find $sln; skipping\n";
return;
}
unless (open SLN, "<", $sln) {
warn "Warning: Can't open $sln; skipping\n";
return;
}
my %projectsByUUID = ();
my $currentProject;
my $state = "initial";
foreach my $line (<SLN>) {
if ($state eq "initial") {
if ($line =~ /^Project\([^\)]+\) = "([^"]+)", "[^"]+", "([^"]+)"\r?$/) {
my $name = $1;
my $uuid = $2;
if (exists $projectsByUUID{$uuid}) {
warn "Warning: Project $name appears more than once in $sln; using first definition\n";
next;
}
$currentProject = {
name => $name,
uuid => $uuid,
dependencies => {},
};
$projectsByUUID{$uuid} = $currentProject;
$state = "inProject";
}
next;
}
if ($state eq "inProject") {
defined($currentProject) or die;
if ($line =~ /^\s*ProjectSection\(ProjectDependencies\) = postProject\r?$/) {
$state = "inDependencies";
} elsif ($line =~ /^EndProject\r?$/) {
$currentProject = undef;
$state = "initial";
}
next;
}
if ($state eq "inDependencies") {
defined($currentProject) or die;
if ($line =~ /^\s*({[^}]+}) = ({[^}]+})\r?$/) {
my $uuid1 = $1;
my $uuid2 = $2;
if (exists $currentProject->{dependencies}->{$uuid1}) {
warn "Warning: UUID $uuid1 listed more than once as dependency of project ", $currentProject->{name}, "\n";
next;
}
$uuid1 eq $uuid2 or warn "Warning: UUIDs in depedency section of project ", $currentProject->{name}, " don't match: $uuid1 $uuid2; using first UUID\n";
$currentProject->{dependencies}->{$uuid1} = 1;
} elsif ($line =~ /^\s*EndProjectSection\r?$/) {
$state = "inProject";
}
next;
}
}
close SLN or warn "Warning: Can't close $sln\n";
my %projectsNotDependedUpon = %projectsByUUID;
CANDIDATE: foreach my $candidateUUID (keys %projectsByUUID) {
foreach my $projectUUID (keys %projectsByUUID) {
next if $candidateUUID eq $projectUUID;
foreach my $dependencyUUID (keys %{$projectsByUUID{$projectUUID}->{dependencies}}) {
if ($candidateUUID eq $dependencyUUID) {
delete $projectsNotDependedUpon{$candidateUUID};
next CANDIDATE;
}
}
}
}
foreach my $project (values %projectsNotDependedUpon) {
printProjectAndDependencies($project, 0, \%projectsByUUID);
}
}
sub printProjectAndDependencies
{
my ($project, $indentLevel, $projectsByUUID) = @_;
print " " x $indentLevel, $project->{name}, "\n";
foreach my $dependencyUUID (keys %{$project->{dependencies}}) {
printProjectAndDependencies($projectsByUUID->{$dependencyUUID}, $indentLevel + 1, $projectsByUUID);
}
}