Print Package Dependency Tree

Using this file , I would like to print the package dependency tree, given a single base package. For example, take a bash package

@ bash # few lines removed requires: coreutils libintl8 libncursesw10 libreadline7 _update-info-dir cygwin 

I would like to find-like output the required packages, a partial example

 bash bash coreutils bash coreutils libattr1 bash coreutils libattr1 libintl8 bash coreutils libattr1 libintl8 libiconv2 bash coreutils libattr1 libintl8 _autorebase bash coreutils libattr1 libintl8 _autorebase rebase bash coreutils libattr1 libintl8 _autorebase rebase dash bash coreutils libattr1 libintl8 _autorebase rebase dash cygwin bash coreutils libattr1 libintl8 _autorebase rebase dash cygwin base-cygwin 

I have this command, but it does not recurs

 #!awk -f $1 == "@" { pkg = $2 } $1 == "requires:" { for (i=2; i<=NF; i++) reqs[pkg][i-1] = $i } END { query = "bash" for (pkg in reqs[query]) { print reqs[query][pkg] } } 
+4
source share
4 answers
 #!/usr/bin/awk -f @include "join" $1 == "@" { apg = $2 } $1 == "requires:" { for (z=2; z<=NF; z++) reqs[apg][z-1] = $z } END { prpg("bash") } function smartmatch(small, large, values) { for (each in large) values[large[each]] return small in values } function prpg(fpg) { if (smartmatch(fpg, spath)) return spath[length(spath)+1] = fpg print join(spath, 1, length(spath)) if (isarray(reqs[fpg])) for (each in reqs[fpg]) prpg(reqs[fpg][each]) delete spath[length(spath)] } 

A source

0
source

With Perl and no comment:

 perl -lne ' $k = $1 if /@\s*(\S+)/; @r=split(); shift @r; $r{$k} = [@r] if /requires:/; END{ $p = "bash"; @l = ( [$p, 0] ); while ($p = pop @l) { next if $d{$p->[0]}++; print " " x $p->[1] . $p->[0]; for $d(@{$r{$p->[0]}}) { push @l, [ $d, $p->[1]+1 ]; } } }' setup.ini 

Awk Version:

 awk '/^@ / { split($0, b); k = b[2]; } /^requires: / { a[k] = $0; } END { p[1] = "bash"; d["bash"] = 0; while (length(p)) { key = p[length(p)]; depth = d[key]; delete p[length(p)]; if (!s[key]++) { printf "%*s %s\n", depth, "", key; split(a[key], r); delete r[1]; for (req in r) { p[length(p) + 1] = r[req]; d[r[req]] = depth + 1; } } } } ' setup.ini 
+6
source

Using GNU awk for true multidimensional arrays (but, obviously, can be changed for other awks):

 $ cat tst.awk /^@/ { pkg = $2 } /^requires:/ { for (i=2;i<=NF;i++) reqs[pkg][$i] } END { prtPkg(root) } function prtPkg(pkg, req) { if (!seen[pkg]++) { printf "%*s%s\n", indent, "", pkg indent += 2 if (pkg in reqs) for (req in reqs[pkg]) prtPkg(req) indent -= 2 } } 

.

 $ cat file3 @ bash whatever requires: libgcc1 libintl8 libncursesw10 libreadline7 _update-info-dir @ libintl8 whatever requires: libiconv2 bash common @ libgcc1 whatever requires: _autorebase common 

.

 $ awk -v root="bash" -f tst.awk file3 bash libncursesw10 libgcc1 _autorebase common _update-info-dir libreadline7 libintl8 libiconv2 

Here is what we need for the new output format you want:

 $ cat file3 @ bash requires: libgcc1 libintl8 libncursesw10 libreadline7 @ libncursesw10 requires: libgcc1 libstdc++6 terminfo libreadline7 

.

 $ cat tst.awk /^@/ { pkg = $2 } /^requires:/ { for (i=2;i<=NF;i++) reqs[pkg][i-1]=$i } END { setMinDepth(root); prtPkg(root) } function setMinDepth(pkg, req, i) { depth++ minDepth[pkg] = ( !(pkg in minDepth) || (depth < minDepth[pkg]) ? depth : minDepth[pkg]) if (depth == minDepth[pkg]) { if (pkg in reqs) for (i=1; i in reqs[pkg]; i++) { req = reqs[pkg][i] setMinDepth(req) } } depth-- } function prtPkg(pkg, req, i) { depth++ if ( (depth == minDepth[pkg]) && (!seen[pkg]++) ) { printf "%*s%s\n", indent, "", pkg indent += 2 if (pkg in reqs) for (i=1; i in reqs[pkg]; i++) { req = reqs[pkg][i] prtPkg(req) } indent -= 2 } depth-- } 

.

 $ awk -v root="bash" -f tst.awk file3 bash libgcc1 libintl8 libncursesw10 libstdc++6 terminfo libreadline7 
+4
source

INI file is no longer available. I want to use a solution, but I do not want to reverse engineer the oriignal file.

0
source

Source: https://habr.com/ru/post/1481092/


All Articles