mirror of
https://git.freebsd.org/ports.git
synced 2025-06-02 11:26:29 -04:00
If any are found then ask if the port should be skipped from removal or removed regardless of the PRs.
505 lines
11 KiB
Bash
Executable file
505 lines
11 KiB
Bash
Executable file
#!/bin/sh -e
|
|
#
|
|
# rmport - remove port(s) from the FreeBSD Ports Collection.
|
|
#
|
|
# Copyright 2006 Vasil Dimov
|
|
# All rights reserved.
|
|
#
|
|
# 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 AUTHOR 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 AUTHOR 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.
|
|
#
|
|
# Authors:
|
|
# Originally written by Vasil Dimov <vd@FreeBSD.org>
|
|
# Others:
|
|
#
|
|
# $FreeBSD$
|
|
#
|
|
# MAINTAINER= vd@FreeBSD.org
|
|
#
|
|
|
|
PORTSDIR=${PORTSDIR:-/usr/ports}
|
|
INDEX=${PORTSDIR}/`make -C ${PORTSDIR} -V INDEXFILE`
|
|
|
|
TODAY=`date -u -v+0d +%Y-%m-%d`
|
|
|
|
SED="sed -i .orig -E"
|
|
# use ~/.ssh/config to set up the desired username if different than $LOGNAME
|
|
PCVS=${PCVS:-cvs -d pcvs.freebsd.org:/home/pcvs}
|
|
|
|
log()
|
|
{
|
|
echo "==> $*" >&2
|
|
}
|
|
|
|
escape()
|
|
{
|
|
# escape characters that may appear in ports' names and
|
|
# break regular expressions
|
|
echo "${1}" |sed -E 's/(\+|\.)/\\\1/g'
|
|
}
|
|
|
|
pkgname()
|
|
{
|
|
make -C ${PORTSDIR}/${1} -V PKGNAME
|
|
}
|
|
|
|
# return category/port if arg is directly port's directory on the filesystem
|
|
find_catport()
|
|
{
|
|
arg=${1}
|
|
|
|
if [ -d "${PORTSDIR}/${arg}" ] ; then
|
|
# arg is category/port
|
|
echo ${arg}
|
|
elif [ -d "${arg}" ] ; then
|
|
# arg is the port's directory somewhere in the filesystem
|
|
# either absolute or relative
|
|
|
|
# get the full path
|
|
rp=`realpath ${arg}`
|
|
|
|
category=`basename \`dirname ${rp}\``
|
|
port=`basename ${rp}`
|
|
echo ${category}/${port}
|
|
else
|
|
echo "What do you mean by \`${arg}'?" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
find_expired()
|
|
{
|
|
EXPVAR=EXPIRATION_DATE
|
|
|
|
find ${PORTSDIR} -mindepth 3 -maxdepth 3 -name "Makefile*" \
|
|
|xargs grep -H ${EXPVAR} \
|
|
|sed -E "s|${PORTSDIR}/?([^/]+/[^/]+)/Makefile:${EXPVAR}=[[:space:]]*([0-9-]{10})$|\2 \1|g" \
|
|
|perl -ne "if ((substr(\$_, 0, 10) cmp '${TODAY}') <= 0) { print(\$_); }" \
|
|
|while read expdate catport ; do \
|
|
echo -n "${expdate} ${catport}: " ; \
|
|
make -C ${PORTSDIR}/${catport} -V DEPRECATED ; \
|
|
done
|
|
}
|
|
|
|
# create temporary checkout directory
|
|
mkcodir()
|
|
{
|
|
log "creating temporary directory"
|
|
d=`mktemp -d -t rmport`
|
|
mkdir ${d}/CVS
|
|
cat > ${d}/CVS/Repository <<REPOSITORY
|
|
We need ./CVS directory in order to create a custom commit message template
|
|
(and put it in ./CVS/Template). Anyway cvs insists on CVS/Repository existence
|
|
although it (hopefully) does not care about its contents.
|
|
REPOSITORY
|
|
touch ${d}/CVS/Template
|
|
log "created ${d}"
|
|
echo "${d}"
|
|
}
|
|
|
|
# checkout common files from the repository
|
|
co_common()
|
|
{
|
|
log "getting CVSROOT/modules, ports/MOVED and ports/LEGAL from repository"
|
|
${PCVS} co CVSROOT/modules ports/MOVED ports/LEGAL
|
|
}
|
|
|
|
# check if some ports depend on the given port
|
|
# XXX Very Little Chance (tm) for breaking INDEX exists:
|
|
# /usr/ports/INDEX may be outdated and not contain recently added dependencies
|
|
# Anyway, it is very unlikely for someone to make a port to depend on a port
|
|
# that has EXPIRATION_DATE set, or /usr/ports/INDEX is really outdated - from
|
|
# before EXPIRATION_DATE being set
|
|
check_dep()
|
|
{
|
|
catport=${1}
|
|
persist=${2}
|
|
alltorm=${3}
|
|
pkgname=`pkgname ${catport}`
|
|
|
|
rmpkgs=""
|
|
rmcatports=""
|
|
for torm in ${alltorm} ; do
|
|
rmpkgs="${rmpkgs:+${rmpkgs}|}`pkgname ${torm}`"
|
|
rmcatports="${rmcatports:+${rmcatports}|}${PORTSDIR}/${torm}/"
|
|
done
|
|
|
|
while : ; do
|
|
log "${catport}: checking dependencies"
|
|
|
|
err=0
|
|
|
|
deps=`grep -E "${pkgname}" ${INDEX} |grep -vE "^(${rmpkgs})" || :`
|
|
if [ -n "${deps}" ] ; then
|
|
log "${catport}: some port(s) depend on ${pkgname}:"
|
|
printf "%s\n" "${deps}" >&2
|
|
err=1
|
|
fi
|
|
|
|
# check if some Makefiles mention the port to be deleted
|
|
portdir_grep="^[^#].*/`basename ${catport}`([[:space:]]|/|$)"
|
|
r="`find ${PORTSDIR} -mindepth 2 -maxdepth 3 \
|
|
\( -name "Makefile*" -or -path "*Mk/*.mk" \) \
|
|
|xargs grep -EH "${portdir_grep}" \
|
|
|grep -vE "^(${rmcatports})" || :`"
|
|
if [ -n "${r}" ] ; then
|
|
log "${catport}: some Makefiles mention ${portdir_grep}:"
|
|
printf "%s\n" "${r}" >&2
|
|
err=1
|
|
fi
|
|
|
|
if [ ${err} -eq 0 ] ; then
|
|
break
|
|
fi
|
|
|
|
if [ ${persist} -eq 0 ] ; then
|
|
break
|
|
fi
|
|
|
|
read -p 'deal with the above issues and hit <enter> when ready' dummy
|
|
done
|
|
}
|
|
|
|
# query GNATS, format and return the result
|
|
get_PRs()
|
|
{
|
|
catport=${1}
|
|
synopsis=${2}
|
|
date_re='[0-9]{4}/[0-9]{2}/[0-9]{2}'
|
|
prnum_re='.+/[0-9]{5,6}'
|
|
synopsis_re='.{10,}'
|
|
|
|
log "${catport}: getting PRs having ${synopsis} in the synopsis"
|
|
|
|
url="http://www.freebsd.org/cgi/query-pr-summary.cgi?text=${synopsis}"
|
|
|
|
raw="`fetch -q -T 20 -o - "${url}"`"
|
|
|
|
if [ -z "${raw}" ] ; then
|
|
log "${catport}: empty result from URL: ${url}"
|
|
exit 1
|
|
fi
|
|
|
|
printf "%s" "${raw}" \
|
|
|sed -nE "s|.*>(${date_re})<.*>(${prnum_re})<.*>(${synopsis_re})</td.*|\1 \2 \3|p" \
|
|
|sort
|
|
}
|
|
|
|
# check if any PRs exist that are related to the port
|
|
check_PRs()
|
|
{
|
|
catport=${1}
|
|
synopsis=${2}
|
|
|
|
PRs="`get_PRs ${catport} "${synopsis}"`" || exit
|
|
|
|
if [ -n "${PRs}" ] ; then
|
|
log "${catport}: PRs found, related to ${synopsis}:"
|
|
printf "%s\n" "${PRs}" >&2
|
|
|
|
echo "you can skip ${catport} and continue with the rest or remove it anyway" >&2
|
|
answer=`ask "do you want to skip ${catport}?"`
|
|
if [ "${answer}" = "y" ] ; then
|
|
return 1
|
|
else
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# checkout port's specific files from the repository
|
|
co_port()
|
|
{
|
|
cat=${1}
|
|
port=${2}
|
|
|
|
log "${cat}/${port}: getting ${cat}/Makefile and port's files from repository"
|
|
${PCVS} co ports/${cat}/Makefile ports/${cat}/${port}
|
|
}
|
|
|
|
# check if anything about the port is mentioned in ports/LEGAL
|
|
check_LEGAL()
|
|
{
|
|
catport=${1}
|
|
pkgname=${2}
|
|
|
|
for checkstr in ${pkgname} ${catport} ; do
|
|
msg="${catport}: checking if ${checkstr} is in ports/LEGAL"
|
|
log "${msg}"
|
|
while grep -i ${checkstr} ports/LEGAL ; do
|
|
read -p "${checkstr} is in ports/LEGAL, remove it and hit <enter> when ready" dummy
|
|
log "${msg}"
|
|
done
|
|
done
|
|
}
|
|
|
|
# remove port's entry from CVSROOT/modules
|
|
edit_modules()
|
|
{
|
|
cat=${1}
|
|
port=${2}
|
|
|
|
log "${cat}/${port}: removing from CVSROOT/modules"
|
|
|
|
portesc=`escape ${port}`
|
|
|
|
${SED} -e "/^(ports_)?(..-)?${portesc}[[:space:]]+ports\/${cat}\/${portesc}\$/d" \
|
|
CVSROOT/modules
|
|
}
|
|
|
|
# add port's entry to ports/MOVED
|
|
edit_MOVED()
|
|
{
|
|
catport=${1}
|
|
|
|
DEPRECATED="`make -C ${PORTSDIR}/${catport} -V DEPRECATED`"
|
|
DEPRECATED=${DEPRECATED:+: ${DEPRECATED}}
|
|
if [ -n "`make -C ${PORTSDIR}/${catport} -V EXPIRATION_DATE`" ] ; then
|
|
REASON="Has expired${DEPRECATED}"
|
|
else
|
|
REASON="Removed${DEPRECATED}"
|
|
fi
|
|
|
|
log "${catport}: adding entry to ports/MOVED"
|
|
|
|
echo "${catport}||${TODAY}|${REASON}" >> ports/MOVED
|
|
}
|
|
|
|
# remove port from category/Makefile
|
|
edit_Makefile()
|
|
{
|
|
cat=${1}
|
|
port=${2}
|
|
|
|
log "${cat}/${port}: removing from ${cat}/Makefile"
|
|
|
|
portesc=`escape ${port}`
|
|
|
|
${SED} -e "/^[[:space:]]*SUBDIR[[:space:]]*\+=[[:space:]]*${portesc}([[:space:]]+#.*)?$/d" \
|
|
ports/${cat}/Makefile
|
|
}
|
|
|
|
# remove port's files
|
|
rm_port()
|
|
{
|
|
catport=${1}
|
|
|
|
log "${catport}: removing port's files"
|
|
|
|
${PCVS} rm `find ports/${catport} -type f -not -path "*/CVS/*" -delete -print`
|
|
}
|
|
|
|
append_Template()
|
|
{
|
|
catport=${1}
|
|
|
|
msg=${catport}
|
|
|
|
EXPIRATION_DATE=`make -C ${PORTSDIR}/${catport} -V EXPIRATION_DATE`
|
|
if [ -n "${EXPIRATION_DATE}" ] ; then
|
|
msg="${EXPIRATION_DATE} ${msg}"
|
|
fi
|
|
|
|
DEPRECATED="`make -C ${PORTSDIR}/${catport} -V DEPRECATED`"
|
|
if [ -n "${DEPRECATED}" ] ; then
|
|
msg="${msg}: ${DEPRECATED}"
|
|
fi
|
|
|
|
log "${catport}: adding entry to commit message template"
|
|
|
|
echo "${msg}" >> ./CVS/Template
|
|
}
|
|
|
|
# diff
|
|
diff()
|
|
{
|
|
log "creating diff"
|
|
|
|
diffout=${codir}/diff
|
|
|
|
${PCVS} diff -u CVSROOT/modules ports > ${diffout} 2>&1 || :
|
|
|
|
read -p "hit <enter> to view cvs diff output" dummy
|
|
|
|
# give this to the outside world so it can be showed to the committer
|
|
# and removed when we are done
|
|
echo ${diffout}
|
|
}
|
|
|
|
ask()
|
|
{
|
|
question=${1}
|
|
|
|
answer=x
|
|
while [ "${answer}" != "y" -a "${answer}" != "n" ] ; do
|
|
read -p "${question} [yn] " answer
|
|
done
|
|
|
|
echo ${answer}
|
|
}
|
|
|
|
# ask for confirmation and commit
|
|
commit()
|
|
{
|
|
answer=`ask "do you want to commit?"`
|
|
|
|
if [ "${answer}" = "y" ] ; then
|
|
${PCVS} ci CVSROOT/modules ports
|
|
fi
|
|
}
|
|
|
|
cleanup()
|
|
{
|
|
diffout=${1}
|
|
codir=${2}
|
|
|
|
log "cleaning up"
|
|
|
|
rm ${diffout}
|
|
|
|
rm CVS/Entries.Log CVS/Repository CVS/Template
|
|
rmdir CVS
|
|
|
|
# release cvs directories
|
|
${PCVS} rel -d CVSROOT ports
|
|
|
|
cd /
|
|
rmdir ${codir}
|
|
}
|
|
|
|
usage()
|
|
{
|
|
echo "Usage:" >&2
|
|
echo "" >&2
|
|
echo "find expired ports:" >&2
|
|
echo "${0} -F" >&2
|
|
echo "" >&2
|
|
echo "remove port(s):" >&2
|
|
echo "${0} category1/port1 [ category2/port2 ... ]" >&2
|
|
echo "" >&2
|
|
echo "remove all expired ports (as returned by -F):" >&2
|
|
echo "${0} -a" >&2
|
|
echo "" >&2
|
|
echo "just check dependencies:" >&2
|
|
echo "${0} -d category/port" >&2
|
|
echo "" >&2
|
|
echo "just check if any related PRs exist:" >&2
|
|
echo "${0} -p synopsis" >&2
|
|
|
|
exit 64
|
|
}
|
|
|
|
# main
|
|
|
|
if [ ${#} -eq 0 -o "${1}" = "-h" -o "${1}" = "--help" ] ; then
|
|
usage
|
|
fi
|
|
|
|
if [ ${1} = "-d" ] ; then
|
|
if [ ${#} -ne 2 ] ; then
|
|
usage
|
|
fi
|
|
catport=`find_catport ${2}`
|
|
check_dep ${catport} 0 ${catport}
|
|
exit
|
|
fi
|
|
|
|
if [ ${1} = "-p" ] ; then
|
|
if [ ${#} -ne 2 ] ; then
|
|
usage
|
|
fi
|
|
get_PRs "dummy" ${2}
|
|
exit
|
|
fi
|
|
|
|
if [ ${1} = "-F" ] ; then
|
|
if [ ${#} -ne 1 ] ; then
|
|
usage
|
|
fi
|
|
find_expired
|
|
exit
|
|
fi
|
|
|
|
if [ ${1} = "-a" ] ; then
|
|
if [ ${#} -ne 1 ] ; then
|
|
usage
|
|
fi
|
|
${0} `find_expired |cut -f 2 -d ' ' |cut -f 1 -d :`
|
|
exit
|
|
fi
|
|
|
|
codir=`mkcodir`
|
|
cd ${codir}
|
|
|
|
co_common
|
|
|
|
for catport in $* ; do
|
|
# convert to category/port
|
|
catport=`find_catport ${catport}`
|
|
cat=`dirname ${catport}`
|
|
port=`basename ${catport}`
|
|
# remove any trailing slashes
|
|
catport="${cat}/${port}"
|
|
pkgname=`pkgname ${catport}`
|
|
|
|
check_dep ${catport} 1 "${*}"
|
|
|
|
if ! check_PRs ${catport} ${port} ; then
|
|
continue
|
|
fi
|
|
|
|
co_port ${cat} ${port}
|
|
|
|
check_LEGAL ${catport} ${pkgname}
|
|
|
|
# everything seems ok, edit the files
|
|
|
|
edit_modules ${cat} ${port}
|
|
|
|
edit_MOVED ${catport}
|
|
|
|
edit_Makefile ${cat} ${port}
|
|
|
|
rm_port ${catport}
|
|
|
|
append_Template ${catport}
|
|
done
|
|
|
|
# give a chance to the committer to edit files by hand and recreate/review
|
|
# the diff afterwards
|
|
answer=y
|
|
while [ "${answer}" = "y" ] ; do
|
|
diffout=`diff`
|
|
|
|
# EDITOR instead of PAGER because vim has nice syntax highlighting ;-)
|
|
${EDITOR} ${diffout}
|
|
|
|
echo "you can now edit files under ${codir}/ by hand" >&2
|
|
answer=`ask "do you want to recreate the diff?"`
|
|
done
|
|
|
|
commit
|
|
|
|
cleanup ${diffout} ${codir}
|
|
|
|
# EOF
|