1#!/usr/bin/perl -w 2 3# Copyright (C) 2008 Apple Inc. All Rights Reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions 7# are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 14# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26use strict; 27use File::Basename; 28 29sub printDependencyTree($); 30 31my $basename = basename($0); 32@ARGV or die "Usage: $basename sln1 [sln2 sln3...]"; 33 34foreach my $sln (@ARGV) { 35 printDependencyTree($sln); 36} 37 38exit; 39 40sub printDependencyTree($) 41{ 42 my ($sln) = @_; 43 44 unless (-f $sln) { 45 warn "Warning: Can't find $sln; skipping\n"; 46 return; 47 } 48 49 unless (open SLN, "<", $sln) { 50 warn "Warning: Can't open $sln; skipping\n"; 51 return; 52 } 53 54 my %projectsByUUID = (); 55 my $currentProject; 56 57 my $state = "initial"; 58 foreach my $line (<SLN>) { 59 if ($state eq "initial") { 60 if ($line =~ /^Project\([^\)]+\) = "([^"]+)", "[^"]+", "([^"]+)"\r?$/) { 61 my $name = $1; 62 my $uuid = $2; 63 if (exists $projectsByUUID{$uuid}) { 64 warn "Warning: Project $name appears more than once in $sln; using first definition\n"; 65 next; 66 } 67 $currentProject = { 68 name => $name, 69 uuid => $uuid, 70 dependencies => {}, 71 }; 72 $projectsByUUID{$uuid} = $currentProject; 73 74 $state = "inProject"; 75 } 76 77 next; 78 } 79 80 if ($state eq "inProject") { 81 defined($currentProject) or die; 82 83 if ($line =~ /^\s*ProjectSection\(ProjectDependencies\) = postProject\r?$/) { 84 $state = "inDependencies"; 85 } elsif ($line =~ /^EndProject\r?$/) { 86 $currentProject = undef; 87 $state = "initial"; 88 } 89 90 next; 91 } 92 93 if ($state eq "inDependencies") { 94 defined($currentProject) or die; 95 96 if ($line =~ /^\s*({[^}]+}) = ({[^}]+})\r?$/) { 97 my $uuid1 = $1; 98 my $uuid2 = $2; 99 if (exists $currentProject->{dependencies}->{$uuid1}) { 100 warn "Warning: UUID $uuid1 listed more than once as dependency of project ", $currentProject->{name}, "\n"; 101 next; 102 } 103 104 $uuid1 eq $uuid2 or warn "Warning: UUIDs in depedency section of project ", $currentProject->{name}, " don't match: $uuid1 $uuid2; using first UUID\n"; 105 106 $currentProject->{dependencies}->{$uuid1} = 1; 107 } elsif ($line =~ /^\s*EndProjectSection\r?$/) { 108 $state = "inProject"; 109 } 110 111 next; 112 } 113 } 114 115 close SLN or warn "Warning: Can't close $sln\n"; 116 117 my %projectsNotDependedUpon = %projectsByUUID; 118 CANDIDATE: foreach my $candidateUUID (keys %projectsByUUID) { 119 foreach my $projectUUID (keys %projectsByUUID) { 120 next if $candidateUUID eq $projectUUID; 121 foreach my $dependencyUUID (keys %{$projectsByUUID{$projectUUID}->{dependencies}}) { 122 if ($candidateUUID eq $dependencyUUID) { 123 delete $projectsNotDependedUpon{$candidateUUID}; 124 next CANDIDATE; 125 } 126 } 127 } 128 } 129 130 foreach my $project (values %projectsNotDependedUpon) { 131 printProjectAndDependencies($project, 0, \%projectsByUUID); 132 } 133} 134 135sub printProjectAndDependencies 136{ 137 my ($project, $indentLevel, $projectsByUUID) = @_; 138 139 print " " x $indentLevel, $project->{name}, "\n"; 140 foreach my $dependencyUUID (keys %{$project->{dependencies}}) { 141 printProjectAndDependencies($projectsByUUID->{$dependencyUUID}, $indentLevel + 1, $projectsByUUID); 142 } 143} 144