pkgsrc/pkgtools/pkgtasks/files/directories.subr
jlam 3c11e11daa Update pkgtools/pkgtasks to version 1.10.
Change the output of the "directories" and "files" tasks to be less
verbose by halving the number of lines in the most common cases.
2017-06-03 23:54:53 +00:00

402 lines
12 KiB
Text

# Copyright (c) 2017 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.
#
# 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
# directories.subr -- directory management for packages
#
# SYNOPSIS
# task_directories [-s] add | remove | perms
# task_directories check-add | check-remove | check-perms
#
# DESCRIPTION
# The task_directories function supports six actions: "add", "remove",
# "perms", "check-add", "check-remove", and "check-perms".
#
# The available options are as follows:
#
# -s Silent; don't write to standard output.
#
# The task_directories function reads standard input line by line and
# looks for lines of the form:
#
# # DIR: <directory> <flags> [<mode> [<user> [<group>]]]
#
# If directory path is relative, then it is assumed to be relative to
# ${PKG_PREFIX}.
#
# The third field in each line is set of flags with the following
# meaning:
#
# f ignore ${PKG_CONFIG} value
# m directory is created
# o directory is owned by the package
# . placeholder flag to ensure the field is non-empty
#
# The "add" action creates the directory and sets the permissions on
# the directory if given. A reference count for the directory will
# be added for the package.
#
# The "remove" action removes the directory. A reference count for
# the directory will be removed for the package.
#
# The "perms" action sets the mode and permissions on the directory
# if they are given.
#
# The "check-add" action will check whether the directory exists or
# otherwise writes a message to standard output noting the missing
# directory.
#
# The "check-remove" action will check whether the directory has
# been removed or otherwise writes a message to standard output
# noting the directory still exist.
#
# The "check-perms" action will check whether the directory has the
# correct permissions or otherwise writes a message to standard
# output noting the directory has incorrect permissions.
#
# RETURN VALUES
# The "add", "remove", and "perms" actions return 0 if they are
# successful for all directories, and >0 if an error occurs.
#
# The "check-add", "check-remove", and "check-perms" actions return
# >0 if they write informative messages, and return 0 otherwise.
#
# ENVIRONMENT
# The following variables are used if they are set:
#
# PKGNAME
# The name of the package.
#
# PKG_CONFIG
# If ${PKG_CONFIG} is a "truthy" value, then the "add" and
# "remove" actions are allowed to make changes to the
# filesystem as needed.
#
# PKG_CONFIG_PERMS
# If ${PKG_CONFIG_PERMS} is a "truthy" value, then the
# "perms" action is allowed to make changes to the
# filesystem as needed.
#
# PKG_DESTDIR
# A "destdir" prefix that is prepended to all filesystem
# paths. The default value is the empty string.
#
# PKG_PREFIX
# The installation prefix of the package. The default is
# "/usr/pkg".
#
# RMDIR The name or path to the rmdir(1) utility.
#
# TASK_MSG
# String prepended to all normal message written to
# standard output.
#
__task_directories__="yes"
task_load echo
task_load makedir
task_load permissions
task_load refcount
task_load truthy
task_load valid_options
task_directories()
{
: ${RMDIR:=rmdir}
: ${PKG_PREFIX:=/usr/pkg}
: ${PKGNAME:=${0##*/}}
: ${PKG_CONFIG:=yes}
: ${PKG_CONFIG_PERMS:=yes}
: ${TASK_MSG:=""}
local arg
local echo="task_echo"
local OPTIND=1
while getopts ":s" arg "$@"; do
case $arg in
s) echo=":" ;;
*) return 127 ;;
esac
done
shift $(( ${OPTIND} - 1 ))
[ $# -gt 0 ] || return 127
local action="$1"; shift
case $action in
add|remove|perms|check-add|check-remove|check-perms)
: "valid actions" ;;
*) return 0 ;;
esac
# Guard against ${PKG_PREFIX} == "/".
local prefix
case ${PKG_PREFIX}/ in
//) prefix= ;;
*) prefix=${PKG_PREFIX} ;;
esac
local pkg_config="yes"
local pkg_config_perms="yes"
task_is_truthy "${PKG_CONFIG}" || pkg_config=
task_is_truthy "${PKG_CONFIG_PERMS}" || pkg_config_perms=
local result line_result
local msg
local owned makedir removedir changes
local refcount
result=0
local d_path
local hash tag path flags mode user group
while read hash tag path flags mode user group; do
# Filter for "# DIR:".
case $hash/$tag in
"#/DIR:")
: "use this line" ;;
*) continue ;;
esac
task_valid_options "$flags" "fmo." || continue
# Canonicalize paths.
case $path in
"") # skip lines without any required args
continue ;;
[!/]*) path="$prefix/$path" ;;
esac
d_path="${PKG_DESTDIR}$path"
msg=
case $mode/$user/$group in
//) msg="$d_path" ;;
[!/]*//)
msg="$d_path (m=$mode)" ;;
[!/]*/[!/]*/)
msg="$d_path (m=$mode, o=$user)" ;;
[!/]*/[!/]*/[!/]*)
msg="$d_path (m=$mode, o=$user, g=$group)" ;;
esac
# Set owner values if the directory should be owned by this package.
owned=
dir_msg="directory"
case $flags in
*o*) owned="yes"
dir_msg="owned directory"
if task_refcount prop_exists dirs "$path" owner; then
# previous owner detected
if task_refcount prop_match dirs "$path" owner; then
: "same owner"
else
# conflicting owners; failure event
$echo "${TASK_MSG}! directory owner conflict: $d_path"
result=1
continue
fi
fi ;;
esac
makedir=
case $flags in
*m*) makedir="seen"
case $flags in
*f*) # "f" always implies makedir.
makedir="yes" ;;
*) # otherwise, makedir only if PKG_CONFIG is truthy.
[ -z "$pkg_config" ] || makedir="yes" ;;
esac ;;
esac
removedir=
case $flags in
*) removedir="seen"
case $flags in
*f*) # "f" always implies removedir.
removedir="yes" ;;
*) # otherwise, removedir only if PKG_CONFIG is truthy.
[ -z "$pkg_config" ] || removedir="yes" ;;
esac ;;
esac
line_result=0
changes=
case $action in
add) refcount="yes"
task_refcount exists dirs "$path" || refcount=
if task_refcount add dirs "$path"; then
if [ -n "$owned" ]; then
# Directory is owned by this package.
if task_refcount prop_put dirs "$path" owner; then
: "directory owner property added"
else
line_result=1
fi
fi
if [ $line_result -gt 0 ]; then
: "skip directory creation"
elif [ -d "$d_path" ]; then
# Directory already exists.
if [ -z "$refcount" ]; then
task_refcount prop_put dirs "$path" preexist || line_result=1
fi
# Only warn if directory exists if it should be owned.
if [ -n "$owned" ]; then
$echo "${TASK_MSG}! $dir_msg already exists: $d_path"
fi
elif [ -z "$makedir" ]; then
: "directory is never created"
elif [ "$makedir" = "seen" ]; then
$echo "${TASK_MSG}! $dir_msg creation skipped: $d_path"
elif task_makedir "$d_path"; then
# Defer writing output until permissions are set.
#$echo "${TASK_MSG}> $dir_msg created: $d_path"
changes="$changes create"
else
$echo "${TASK_MSG}! $dir_msg not created: $d_path"
line_result=1
fi
else
# add refcount failed; skip to next line
$echo "${TASK_MSG}! refcount add failure: directories $path"
result=1
continue
fi ;;
check-add)
if [ -d "$d_path" ]; then
: "directory already exists"
elif [ -n "$makedir" ]; then
task_echo "!!! INFO: ${PKGNAME}: Create directory: $msg"
line_result=1
fi ;;
esac
if [ $line_result -eq 0 ]; then
case $mode/$user/$group in
//) case " $changes " in
*" create "*)
$echo "${TASK_MSG}> $dir_msg created: $d_path" ;;
*) : "no permissions to set" ;;
esac ;;
*) case $action in
add|perms)
task_refcount prop_put dirs "$path" permissions "$mode" "$user" "$group" || line_result=1
if [ ! -d "$d_path" ]; then
$echo "${TASK_MSG}! $dir_msg permissions not set on missing: $msg"
if [ "$makedir" = "yes" ]; then
# The directory should have been created; otherwise,
# it's an error.
#
line_result=1
fi
elif [ "$action" = "perms" -a -z "$pkg_config_perms" ]; then
# "perms" action, but PKG_CONFIG_PERMS is not trutyy.
$echo "${TASK_MSG}! $dir_msg permissions skipped: $msg"
elif task_set_permissions "$d_path" "$mode" "$user" "$group"; then
case " $changes " in
*" create "*)
$echo "${TASK_MSG}> $dir_msg created: $msg" ;;
*) $echo "${TASK_MSG}> $dir_msg permissions set: $msg" ;;
esac
else
case " $changes " in
*" create "*)
$echo "${TASK_MSG}> $dir_msg created: $d_path" ;;
*) : "no directory was created" ;;
esac
$echo "${TASK_MSG}! $dir_msg permissions not set: $msg"
line_result=1
fi ;;
check-add|check-perms)
if [ -d "$d_path" ] &&
task_check_permissions "$d_path" "$mode" "$user" "$group"; then
: "directory has correct permissions"
else
task_echo "!!! INFO: ${PKGNAME}: Set directory permissions: $msg"
line_result=1
fi
esac ;;
esac
fi
if [ $line_result -eq 0 ]; then
case $action in
remove) if task_refcount remove dirs "$path"; then
if task_refcount exists dirs "$path"; then
# refcount is not zero
if [ -n "$owned" ]; then
# owned directory has existing references; failure event.
$echo "${TASK_MSG}! directory owned but references exist: $path"
line_result=1
fi
else
# no more references
if task_refcount prop_exists dirs "$path" preexist; then
: "directory is preexisting"
elif [ ! -d "$d_path" ]; then
: "directory already removed"
elif [ "$removedir" = "yes" ]; then
${RMDIR} -p "$d_path" 2>/dev/null
fi
# Only warn if the directory is owned by the package.
if [ -n "$owned" ]; then
if [ -d "$d_path" ]; then
$echo "${TASK_MSG}! $dir_msg not removed: $d_path"
else
$echo "${TASK_MSG}> $dir_msg removed: $d_path"
fi
fi
# delete the reference count
task_refcount delete dirs "$path"
fi
else
# remove refcount failed
$echo "${TASK_MSG}! refcount remove failure: directories $path"
line_result=1
fi ;;
check-remove)
if task_refcount exists dirs "$path"; then
: "refcount is not zero"
elif [ ! -d "$d_path" ]; then
: "directory already removed"
elif [ -n "$removedir" -a -n "$owned" ]; then
# Only warn if the directory is owned by the package.
task_echo "!!! INFO: ${PKGNAME}: Remove $dir_msg: $d_path"
line_result=1
fi
esac
fi
if [ $line_result -gt 0 ]; then
# Undo changes if there was an error.
case " $changes " in
*" create "*)
${RMDIR} -p "$d_path" 2>/dev/null ;;
esac
fi
[ $line_result -eq 0 ] || result=1
done
return $result
}