diff options
author | jlam <jlam@pkgsrc.org> | 2006-01-18 00:10:07 +0000 |
---|---|---|
committer | jlam <jlam@pkgsrc.org> | 2006-01-18 00:10:07 +0000 |
commit | 5c5ac03ec12536d13869d4edf8c7c97b2796b9a1 (patch) | |
tree | f4fe93f3ca14bb30bc4e732fd5d5db1b7057e3bf /mk/scripts | |
parent | d188673373daf5e22cfec4bf77f47abac9a3a413 (diff) | |
download | pkgsrc-5c5ac03ec12536d13869d4edf8c7c97b2796b9a1.tar.gz |
Create a standalone awk script, depends-depth-first.awk, that encapsulates
the code that performs the dependency graph traversal (in depth-first
fashion). This script has a hook that allows executing a shell command
line upon visiting a dependency's package directory in either prefix
or postfix order, and may be used to simplify the code in bsd.pkg.mk
that iterates over dependencies.
This awk script requires the target "show-depends-pkgpaths", which is
defined in a new Makefile pkgsrc/mk/bsd.utils.mk. This file should
accumulate "utility" targets that current exist in bsd.pkg.mk, i.e.,
"helper" targets for various actions.
Diffstat (limited to 'mk/scripts')
-rwxr-xr-x | mk/scripts/depends-depth-first.awk | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/mk/scripts/depends-depth-first.awk b/mk/scripts/depends-depth-first.awk new file mode 100755 index 00000000000..87ef4c3e25e --- /dev/null +++ b/mk/scripts/depends-depth-first.awk @@ -0,0 +1,273 @@ +#!/usr/bin/awk -f +# +# $NetBSD: depends-depth-first.awk,v 1.1 2006/01/18 00:10:07 jlam Exp $ +# +# Copyright (c) 2006 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Johnny C. Lam. +# +# 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. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the NetBSD +# Foundation, Inc. and its contributors. +# 4. Neither the name of The NetBSD Foundation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``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 THE FOUNDATION 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. +# + +###################################################################### +# +# NAME +# depends-depth-first.awk -- traverse the dependency graph +# +# SYNOPSIS +# depends-depth-first.awk -- [options] pkgpath ... +# +# DESCRIPTION +# depends-depth-first.awk performs a depth-first traversal of the +# dependency graph associated with the package directories specified +# on the command line, and provides a hook to allow a shell command +# line to be executed within each package directory during traversal. +# +# OPTIONS +# The following command line arguments are supported. +# +# -- This is a mandatory option and must always be the +# first option specified. +# +# -c cmdline Execute the specified command line when visiting +# a package directory during traversal. If the -c +# option is not given, then the default action is +# to output the package directory name. +# +# -d depends-type +# When searching for a package's dependencies, use +# the named "depends-type". This is passed as the +# DEPENDS_TYPE argument of the "show-depends-pkgpaths" +# target. By default, the dependency type is "all". +# +# -o order The dependencies are visited during the dependency +# graph traversal in the named order, which is either +# "prefix" or "postfix". By default, dependencies +# are visited in "postfix" order. +# +# -r If the -r option is specified, then the package +# directories specified on the command-line are +# also visited. +# +# -s pkgsrcdir Use the specified directory as the path to the +# pkgsrc directory tree. By default, this is the +# value stored in the PKGSRCDIR environment variable. +# +# ENVIRONMENT +# PKGSRCDIR This is the location of the pkgsrc directory tree, +# which defaults to "/usr/pkgsrc". +# +###################################################################### + +###################################################################### +# +# Initialize global variables, parse the command-line arguments, and +# invoke the main() function +# +###################################################################### +BEGIN { + ECHO = ENVIRON["ECHO"] ? ENVIRON["ECHO"] : "echo" + MAKE = ENVIRON["MAKE"] ? ENVIRON["MAKE"] : "make" + PKGSRCDIR = ENVIRON["PKGSRCDIR"] ? ENVIRON["PKGSRCDIR"] : "/usr/pkgsrc" + TEST = ENVIRON["TEST"] ? ENVIRON["TEST"] : "test" + + self = "depends-depth-first.awk" + cmd_hook = "" + depends_type = "all" + do_root = 0 + walk_order = "postfix" + + ARGSTART = 1 + parse_options() + main() +} + +###################################################################### +# +# usage() +# Output the usage message to standard error. +# +###################################################################### +function usage() { + print "usage: " self " [-- [-c cmdline] [-d depends-type] [-o order] [-r] [-s pkgsrcdir]] [pkgpath ...]" > "/dev/stderr" +} + +###################################################################### +# +# parse_options() +# Adjust global variables based on the options passed on the +# command line. After this function exists, ARGSTART is set +# to the index in the ARGV array of the first package directory +# in which to begin the traversal. +# +###################################################################### +function parse_options( option) { + if (ARGV[ARGSTART] == "--") { + ARGSTART++ + } + while (ARGSTART < ARGC) { + option = ARGV[ARGSTART] + if (option == "-c") { + cmd_hook = ARGV[ARGSTART + 1] + ARGSTART += 2 + } else if (option == "-d") { + depends_type = ARGV[ARGSTART + 1] + ARGSTART += 2 + } else if (option == "-o") { + walk_order = ARGV[ARGSTART + 1] + ARGSTART += 2 + } else if (option == "-r") { + do_root = 1 + ARGSTART++ + } else if (option == "-s") { + PKGSRCDIR = ARGV[ARGSTART + 1] + ARGSTART += 2 + } else if (option == "--") { + ARGSTART++ + break; + } else if (match(option, /^-.*/) != 0) { + option = substr(option, RSTART + 1, RLENGTH) + print self ": unknown option -- " option > "/dev/stderr" + usage() + exit 1 + } else { + ARGSTART++ + } + } + if (walk_order !~ /prefix|postfix/) { + print self ": unknown walk order -- " walk_order > "/dev/stderr" + usage() + exit 1 + } +} + +###################################################################### +# +# main() +# This provides an implementation of the well-known non-recursive +# algorithm for depth-first-traversal of a graph, but with a +# small modification to allow visiting the nodes (package directories) +# in either "prefix" or "postfix" order. This more closely mimics +# a function stack than the usual non-recursive DFS algorithm. +# +###################################################################### +function main( cmd, depends_pkgpath, dir, pkgpath) { + # + # Push the given package directories onto the stack. + while (ARGC >= ARGSTART) { + ARGC--; + cmd = TEST " -d " PKGSRCDIR "/" ARGV[ARGC] + if (system(cmd) == 0) { + if (do_root == 0) { + root[ARGV[ARGC]] = ARGV[ARGC] + } + push(dir_stack, ARGV[ARGC]) + } + } + + # Depth-first traversal of dependency graph. + while (!empty(dir_stack)) { + pkgpath = top(dir_stack) + if (status[pkgpath] == "walked") { + if (walk_order == "postfix") { + visit(pkgpath) + } + pop(dir_stack) + continue + } + status[pkgpath] = "walked" + if (walk_order == "prefix") { + visit(pkgpath) + } + + # Grab the "depends_type" dependencies of the current + # package and push them onto the stack. We use the + # "show-depends-pkgpaths" target to fetch this information. + # + dir = PKGSRCDIR "/" pkgpath + cmd = "if " TEST " -d " dir "; then cd " dir " && " MAKE " show-depends-pkgpaths DEPENDS_TYPE=\"" depends_type "\"; fi" + while (cmd | getline depends_pkgpath) { + if (status[depends_pkgpath] == "") { + status[depends_pkgpath] = "pushed" + push(dir_stack, depends_pkgpath) + } + } + close(cmd) + } + exit 0 +} + +###################################################################### +# +# visit(pkgpath) +# Visit the package directory by running the shell command +# specified on the command line and stored in "cmd_hook". +# If "cmd_hook" is empty, then just print the package directory +# name. +# +###################################################################### +function visit(pkgpath, cmd, dir) { + if ((do_root == 0) && (root[pkgpath] != "")) { + return + } + if (cmd_hook == "") { + print pkgpath + } else { + dir = PKGSRCDIR "/" pkgpath + cmd = "cd " dir " && " cmd_hook + system(cmd) + } +} + +###################################################################### +# +# empty(stack) +# top(stack) +# push(stack, element) +# pop(stack) +# The well-known functions associated with a FIFO. +# +###################################################################### +function empty(stack) { + return (stack[0] <= 0) +} + +function top(stack) { + return stack[stack[0]]; +} + +function push(stack, elt) { + stack[++stack[0]] = elt +} + +function pop(stack) { + stack[0]-- +} |