#!/bin/sh # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 # \ if /usr/bin/which -s port-tclsh; then exec port-tclsh "$0" -i `which port-tclsh` "$@"; else exec /usr/bin/tclsh "$0" "$@"; fi # # Run a recursive dependency listing against a given port, outputing # a Graphviz graph description. To create a graphical representation # of that graph, run for example: # $ port-depgraph apache2 | dot -Tpng -o apache2.png set MY_VERSION 0.2 array set portsSeen {} proc printUsage {} { puts "Usage: $::argv0 \[-hivV\] \[-p macports-prefix\] port-name \[variants...\]" puts " -h This help" puts " -i Specify port-tclsh" puts " -p Use a different MacPorts prefix" puts " (defaults to /opt/local)" puts " -v verbose output, includes dependency labels" puts " -V show version and MacPorts version being used" puts "" puts "port-name is the name of a port whose dependencies should be shown" puts "variants is the list of variants to enable/disable: +one -two..." } proc dependenciesForPort {portName variantInfo} { set dependencyList [list] set portSearchResult [mportlookup $portName] if {[llength $portSearchResult] < 1} { puts "Warning: port \"$portName\" not found" return [list] } array set portInfo [lindex $portSearchResult 1] set mport [mportopen $portInfo(porturl) [list subport $portName] $variantInfo] array unset portInfo array set portInfo [mportinfo $mport] mportclose $mport array set dependencyDictionary {depends_fetch fetch depends_extract extract depends_build build depends_lib lib depends_run run} foreach dependencyType [array names dependencyDictionary] { if {[info exists portInfo($dependencyType)] && [string length $portInfo($dependencyType)] > 0} { foreach dependency $portInfo($dependencyType) { set afterColon [expr {[string last ":" $dependency] + 1}] lappend dependencyList [list $dependencyDictionary($dependencyType) [string range $dependency 0 [expr [string first ":" $dependency] - 1]] [string range $dependency $afterColon end]] } } } return $dependencyList } proc print_dependencies {dependencyArray portName verbose} { upvar $dependencyArray portDependencies global portsSeen if {[info exists portsSeen($portName)]} { return } set portsSeen($portName) 1 foreach aList $portDependencies($portName) { set aType [lindex $aList 0] set aBy [lindex $aList 1] set aPort [lindex $aList 2] set color "black" if {$aType == "lus"} { set color "#666666" } elseif {$aType == "fetch"} { set color "#ff00007f" } elseif {$aType == "extract"} { set color "#00ff007f" } elseif {$aType == "build"} { set color "#0000ff7f" } set style "solid" if {$aBy == "bin" || $aBy == "lib"} { set style "dashed" } if {!$verbose} { puts [format {"%s" -> "%s" [style="%s", color="%s"]} $portName $aPort $style $color] } else { puts [format {"%s" -> "%s" [style="%s", color="%s", label="%s"]} $portName $aPort $style $color $aBy] } print_dependencies portDependencies $aPort $verbose } } proc find_all_dependencies {portName variantInfo verbose} { array set portDependencies {} set portList [list $portName] while {[llength $portList] > 0} { set aPort [lindex $portList 0] set portDependencies($aPort) [dependenciesForPort $aPort $variantInfo] set portList [lreplace $portList 0 0] foreach possiblyNewPort $portDependencies($aPort) { if {![info exists portDependencies([lindex $possiblyNewPort 2])]} { lappend portList [lindex $possiblyNewPort 2] } } } set portSpec ${portName} foreach {variantName variantFlag} ${variantInfo} { append portSpec { } ${variantFlag}${variantName} } set caption [format {Dependencies of %s} ${portSpec}] set font "Helvetica Neue" set fontBold "$font Bold" puts "strict digraph \"$portName\" \{" puts [format {graph [fontname="%s" fontsize="14" label="%s"]} $fontBold $caption] puts [format {node [fontname="%s"]} $font] puts [format {edge [fontname="%s"]} $font] print_dependencies portDependencies $portName $verbose puts [format { "graph legend" [shape=none fontsize="9" label=<
Legend
depends_lib
depends_run
depends_fetch
depends_extract
depends_build
port:
path:
bin:
lib:
>] } $fontBold ] puts "\}" } # Begin set macportsPrefix /opt/local set verbose 0 set showVersion 0 while {[string index [lindex $::argv 0] 0] == "-" } { switch [string range [lindex $::argv 0] 1 end] { h { printUsage exit 0 } i { set interp_path [lindex $::argv 1] set ::argv [lrange $::argv 1 end] } p { if {[llength $::argv] < 2} { puts "-p needs a path" printUsage exit 1 } set macportsPrefix [lindex $::argv 1] set ::argv [lrange $::argv 1 end] set userPrefix 1 } v { set verbose 1 } V { set showVersion 1 } default { puts "Unknown option [lindex $::argv 0]" printUsage exit 1 } } set ::argv [lrange $::argv 1 end] } # check that default prefix exists if {![info exists userPrefix] && ![file isdirectory $macportsPrefix]} { error "prefix '$macportsPrefix' does not exist; maybe you need to use the -p option?" } if {[info exists interp_path]} { set prefixFromInterp [file dirname [file dirname $interp_path]] # make sure we're running in the port-tclsh associated with the correct prefix if {$prefixFromInterp ne $macportsPrefix} { if {[file executable ${macportsPrefix}/bin/port-tclsh]} { exec ${macportsPrefix}/bin/port-tclsh $argv0 -i ${macportsPrefix}/bin/port-tclsh {*}[lrange $origArgv 2 end] <@stdin >@stdout 2>@stderr } else { exec /usr/bin/tclsh $argv0 {*}[lrange $origArgv 2 end] <@stdin >@stdout 2>@stderr } exit 0 } } else { # older base version source ${macportsPrefix}/share/macports/Tcl/macports1.0/macports_fastload.tcl } package require macports mportinit if {$showVersion} { puts "Version $MY_VERSION" puts "MacPorts version [macports::version]" exit 0 } if {[llength $::argv] == 0} { puts "Error: missing port-name" printUsage exit 1 } set portName [lindex $::argv 0] set ::argv [lrange $::argv 1 end] array set variantInfo {} foreach variantSetting $::argv { set flag [string index $variantSetting 0] set variantName [string range $variantSetting 1 end] set variantInfo($variantName) $flag } find_all_dependencies $portName [array get variantInfo] $verbose