pkgsrc/mk/check/check-files.mk
2020-12-20 19:49:25 +00:00

390 lines
13 KiB
Makefile

# $NetBSD: check-files.mk,v 1.37 2020/12/20 19:49:25 gutteridge Exp $
#
# This file checks that the list of installed files matches the PLIST.
# For that purpose it records the file list of LOCALBASE before and
# after the installation of the package and compares these lists with
# the PLIST.
#
# User-settable variables:
#
# CHECK_FILES
# "yes" to enable the check, "no" to disable it.
#
# Default value: "yes"
#
# CHECK_FILES_STRICT
# When set to "yes", VARBASE and PKG_SYSCONFDIR are checked in
# addition to LOCALBASE.
#
# Package-settable variables:
#
# CHECK_FILES_SKIP
# A list of regular expressions (FIXME: all other checks use shell
# patterns) that names files to be skipped. This is useful to
# avoid getting errors triggered by changes in directories not
# really handled by pkgsrc.
#
_VARGROUPS+= check-files
_USER_VARS.check-files= CHECK_FILES CHECK_FILES_STRICT
_PKG_VARS.check-files= CHECK_FILES_SKIP
CHECK_FILES?= yes
CHECK_FILES_STRICT?= no
# Info index files updated when a new info file is added.
.if defined(INFO_FILES)
CHECK_FILES_SKIP+= ${PREFIX}/.*/dir
.endif
# Perl's perllocal.pod index that is regenerated when a local module
# is added.
#
CHECK_FILES_SKIP+= ${PERL5_INSTALLARCHLIB}/perllocal.pod
# R's index files that are regenerated when a local module
# is added.
#
CHECK_FILES_SKIP+= ${PREFIX}/lib/R/doc/html/packages.html
CHECK_FILES_SKIP+= ${PREFIX}/lib/R/doc/html/search/index.txt
CHECK_FILES_SKIP+= ${PKG_DBDIR}/.*
# We don't care about what's under linux/proc and linux32/proc in Linux
# emulation, which just holds run-time generated data.
#
CHECK_FILES_SKIP+= ${PREFIX}/emul/linux/proc.*
CHECK_FILES_SKIP+= ${PREFIX}/emul/linux32/proc.*
# The reference-count meta-data directory used by the {de,}install scripts.
CHECK_FILES_SKIP+= ${PKG_DBDIR}.refcount.*
# Some people have their distfiles and binary packages below ${LOCALBASE}.
CHECK_FILES_SKIP+= ${PACKAGES}/.*
CHECK_FILES_SKIP+= ${DISTDIR}/.*
# For unprivileged builds, VARBASE is below LOCALBASE.
.if !empty(CHECK_FILES_STRICT:M[Nn][Oo])
CHECK_FILES_SKIP+= ${VARBASE}/.*
.endif
# Files that are outside of ${PREFIX} in directories we already know we'll
# be using for mutable data.
#
.for d in ${MAKE_DIRS} ${OWN_DIRS}
CHECK_FILES_SKIP+= ${d:C/^([^\/])/${PREFIX}\/\1/}.*
.endfor
.for _var_ in MAKE_DIRS_PERMS OWN_DIRS_PERMS
. if empty(${_var_}) || empty(${_var_}:C/.*/4/:M*:S/4 4 4 4//gW)
. for d o g m in ${${_var_}}
CHECK_FILES_SKIP+= ${d:C/^([^\/])/${PREFIX}\/\1/}.*
. endfor
. endif
.endfor
# Mutable X11 font database files
.if (defined(FONTS_DIRS.x11) && !empty(FONTS_DIRS.x11:M*))
CHECK_FILES_SKIP+= ${PREFIX}/.*/encodings.dir
CHECK_FILES_SKIP+= ${PREFIX}/.*/fonts.dir
.endif
.if (defined(FONTS_DIRS.ttf) && !empty(FONTS_DIRS.ttf:M*)) || \
(defined(FONTS_DIRS.type1) && !empty(FONTS_DIRS.type1:M*))
CHECK_FILES_SKIP+= ${PREFIX}/.*/fonts.scale
.endif
.if (defined(FONTS_DIRS.ttf) && !empty(FONTS_DIRS.ttf:M*)) || \
(defined(FONTS_DIRS.type1) && !empty(FONTS_DIRS.type1:M*)) || \
(defined(FONTS_DIRS.x11) && !empty(FONTS_DIRS.x11:M*))
CHECK_FILES_SKIP+= ${PREFIX}/.*/fonts.cache-1
.endif
# Mutable icon theme cache files
.if !empty(ICON_THEMES:M[Yy][Ee][Ss])
CHECK_FILES_SKIP+= ${PREFIX}/share/icons/.*/icon-theme.cache
.endif
# Mutable charset.alias file
CHECK_FILES_SKIP+= ${PREFIX}/lib/charset.alias
# Mutable locale.alias file
CHECK_FILES_SKIP+= ${PREFIX}/share/locale/locale.alias
_CHECK_FILES_SKIP_FILTER= ${GREP} -vx ${CHECK_FILES_SKIP:@f@-e ${DESTDIR:Q}${f:Q}@}
###########################################################################
# These are the files generated and used by the check-files implementation
# used across several check-files targets.
#
# _CHECK_FILES_ERRMSG.* are the files that contain the error
# messages discovered during each stage of file-checking.
#
# _CHECK_FILES_PRE.* are the file lists generated before any files
# from the package are installed.
#
# _CHECK_FILES_POST.* are the file lists generated after all files
# from the package are installed.
#
# The "pre" and "post" file lists are compared against each other to
# determine if the package is installing files where it shouldn't be.
#
_CHECK_FILES_ERRMSG.prefix= ${ERROR_DIR}/check-files-prefix
_CHECK_FILES_PRE.prefix= ${WRKDIR}/.prefix.pre
_CHECK_FILES_POST.prefix= ${WRKDIR}/.prefix.post
_CHECK_FILES_ERRMSG.sysconfdir= ${ERROR_DIR}/.check-files-sysconfdir
_CHECK_FILES_PRE.sysconfdir= ${WRKDIR}/.sysconfdir.pre
_CHECK_FILES_POST.sysconfdir= ${WRKDIR}/.sysconfdir.post
_CHECK_FILES_ERRMSG.varbase= ${ERROR_DIR}/.check-files-varbase
_CHECK_FILES_PRE.varbase= ${WRKDIR}/.varbase.pre
_CHECK_FILES_POST.varbase= ${WRKDIR}/.varbase.post
_CHECK_FILES_ERRMSGS= # empty
_CHECK_FILES_ERRMSGS+= ${_CHECK_FILES_ERRMSG.prefix}
.if empty(CHECK_FILES_STRICT:M[nN][oO])
_CHECK_FILES_ERRMSGS+= ${_CHECK_FILES_ERRMSG.sysconfdir}
_CHECK_FILES_ERRMSGS+= ${_CHECK_FILES_ERRMSG.varbase}
.endif
###########################################################################
# _CHECK_FILES_PRE holds the list of targets that are built as part of
# building the check-files-pre target. These targets should cause the
# "pre" file lists to be generated.
#
_CHECK_FILES_PRE= #
_CHECK_FILES_PRE+= ${_CHECK_FILES_PRE.prefix}
.if empty(CHECK_FILES_STRICT:M[nN][oO])
_CHECK_FILES_PRE+= ${_CHECK_FILES_PRE.sysconfdir}
_CHECK_FILES_PRE+= ${_CHECK_FILES_PRE.varbase}
.endif
###########################################################################
# _CHECK_FILES_POST holds the list of targets that are built as part of
# building the check-files-post target. These targets should cause the
# "post" file lists to be generated.
#
_CHECK_FILES_POST= #
_CHECK_FILES_POST+= ${_CHECK_FILES_POST.prefix}
.if empty(CHECK_FILES_STRICT:M[nN][oO])
_CHECK_FILES_POST+= ${_CHECK_FILES_POST.sysconfdir}
_CHECK_FILES_POST+= ${_CHECK_FILES_POST.varbase}
.endif
.if empty(CHECK_FILES:M[nN][oO])
privileged-install-hook: check-files
.endif
###########################################################################
# check-files-pre and check-files-post targets and subtargets
#
.PHONY: check-files-pre check-files-post
check-files-pre: check-files-pre-message ${_CHECK_FILES_PRE}
check-files-post: check-files-post-message ${_CHECK_FILES_POST}
.PHONY: check-files-pre-message check-files-post-message
check-files-pre-message:
@${STEP_MSG} "Generating pre-install file lists"
check-files-post-message:
@${STEP_MSG} "Generating post-install file lists"
${_CHECK_FILES_PRE.prefix} ${_CHECK_FILES_POST.prefix}:
${RUN} \
${FIND} ${DESTDIR}${PREFIX}/. \( -type f -o -type l \) -print 2>/dev/null \
| ${SED} -e 's,/\./,/,' \
| ${_CHECK_FILES_SKIP_FILTER} \
| ${SORT} > ${.TARGET} \
|| ${TRUE}
${_CHECK_FILES_PRE.sysconfdir} ${_CHECK_FILES_POST.sysconfdir}:
${RUN} \
${FIND} ${DESTDIR}${PKG_SYSCONFDIR}/. -print 2>/dev/null \
| ${SED} -e 's,/\./,/,' \
| ${_CHECK_FILES_SKIP_FILTER} \
| ${SORT} > ${.TARGET} \
|| ${TRUE}
${_CHECK_FILES_PRE.varbase} ${_CHECK_FILES_POST.varbase}:
${RUN} \
${FIND} ${DESTDIR}${VARBASE}/. -print 2>/dev/null \
| ${SED} -e 's,/\./,/,' \
| ${_CHECK_FILES_SKIP_FILTER} \
| ${SORT} > ${.TARGET} \
|| ${TRUE}
###########################################################################
# check-files targets and subtargets
#
.PHONY: check-files-prefix check-files-sysconfdir check-files-varbase
check-files-prefix: ${_CHECK_FILES_ERRMSG.prefix}
check-files-sysconfdir: ${_CHECK_FILES_ERRMSG.sysconfdir}
check-files-varbase: ${_CHECK_FILES_ERRMSG.varbase}
# The check-files target looks at the cookie files generated by the
# check-files-* subtargets, and if they are non-empty, then they
# contain the error messages collected during the build of each
# subtarget.
#
.PHONY: check-files
.if !empty(CHECK_FILES_SUPPORTED:M[nN][oO])
check-files:
@${DO_NADA}
.else
check-files: check-files-message ${_CHECK_FILES_ERRMSGS} error-check
.endif
.PHONY: check-files-message
check-files-message:
@${STEP_MSG} "Checking file-check results for ${PKGNAME}"
# Check ${PREFIX} for files which are not listed in the generated ${PLIST}
# and vice-versa.
#
_CHECK_FILES_DIFF= ${WRKDIR}/.check_files_diff
_CHECK_FILES_ADDED= ${WRKDIR}/.check_files_added
_CHECK_FILES_DELETED= ${WRKDIR}/.check_files_deleted
_CHECK_FILES_EXPECTED= ${WRKDIR}/.check_files_expected
_CHECK_FILES_MISSING= ${WRKDIR}/.check_files_missing
_CHECK_FILES_MISSING_SKIP= ${WRKDIR}/.check_files_missing_skip
_CHECK_FILES_MISSING_REAL= ${WRKDIR}/.check_files_missing_real
_CHECK_FILES_EXTRA= ${WRKDIR}/.check_files_extra
${_CHECK_FILES_DIFF}: ${_CHECK_FILES_PRE.prefix} ${_CHECK_FILES_POST.prefix}
${RUN} \
${DIFF} -u ${_CHECK_FILES_PRE.prefix} \
${_CHECK_FILES_POST.prefix} \
> ${.TARGET} || ${TRUE}
${_CHECK_FILES_ADDED}: ${_CHECK_FILES_DIFF}
${RUN} \
${GREP} '^+/' ${_CHECK_FILES_DIFF} | ${SED} "s|^+||" | ${SORT} \
> ${.TARGET}
${_CHECK_FILES_DELETED}: ${_CHECK_FILES_DIFF}
${RUN} \
${GREP} '^-/' ${_CHECK_FILES_DIFF} | ${SED} "s|^-||" | ${SORT} \
> ${.TARGET}
${_CHECK_FILES_EXPECTED}: plist
${RUN} \
${GREP} '^[^@]' ${PLIST} | ${SED} "s|^|${DESTDIR}${PREFIX}/|" | ${SORT} \
> ${.TARGET}
${_CHECK_FILES_MISSING}: ${_CHECK_FILES_EXPECTED} ${_CHECK_FILES_ADDED}
${RUN} \
${DIFF} -u ${_CHECK_FILES_EXPECTED} ${_CHECK_FILES_ADDED} | \
${GREP} '^-[^-]' | ${SED} "s|^-||" | \
while read file; do \
${TEST} -f "$$file" -o -h "$$file" || ${ECHO} "$$file"; \
done > ${.TARGET}
${_CHECK_FILES_MISSING_REAL}: ${_CHECK_FILES_MISSING}
${RUN} \
${CAT} ${_CHECK_FILES_MISSING} | ${_CHECK_FILES_SKIP_FILTER} \
> ${.TARGET} || ${TRUE}
${_CHECK_FILES_MISSING_SKIP}: \
${_CHECK_FILES_MISSING} \
${_CHECK_FILES_MISSING_REAL}
${RUN} \
${DIFF} -u ${_CHECK_FILES_MISSING} \
${_CHECK_FILES_MISSING_REAL} | \
${GREP} '^-[^-]' | ${SED} "s|^-||" \
> ${.TARGET}
${_CHECK_FILES_EXTRA}: ${_CHECK_FILES_EXPECTED} ${_CHECK_FILES_ADDED}
${RUN} \
${DIFF} -u ${_CHECK_FILES_EXPECTED} ${_CHECK_FILES_ADDED} | \
${GREP} '^+[^+]' | ${SED} "s|^+||" | \
while read file; do \
${TEST} ! -f "$$file" -a ! -h "$$file" || ${ECHO} "$$file"; \
done > ${.TARGET}
${_CHECK_FILES_ERRMSG.prefix}: \
${_CHECK_FILES_DELETED} \
${_CHECK_FILES_MISSING} \
${_CHECK_FILES_MISSING_REAL} \
${_CHECK_FILES_MISSING_SKIP} \
${_CHECK_FILES_EXTRA}
${RUN}${RM} -f ${.TARGET}
${RUN} \
if ${_NONZERO_FILESIZE_P} ${_CHECK_FILES_DELETED}; then \
${ECHO} "The following files have been deleted" \
"from ${PREFIX}!"; \
${SED} "s|^| |" ${_CHECK_FILES_DELETED}; \
fi >> ${.TARGET}
${RUN} \
if ${_NONZERO_FILESIZE_P} ${_CHECK_FILES_MISSING_REAL}; then \
${ECHO} "************************************************************"; \
${ECHO} "The following files are in the" \
"PLIST but not in ${DESTDIR}${PREFIX}:"; \
${SED} "s|^| |" ${_CHECK_FILES_MISSING_REAL}; \
fi >> ${.TARGET}
${RUN} \
if ${_NONZERO_FILESIZE_P} ${_CHECK_FILES_EXTRA}; then \
${ECHO} "************************************************************"; \
${ECHO} "The following files are in" \
"${DESTDIR}${PREFIX} but not in the PLIST:"; \
${SED} "s|^| |" ${_CHECK_FILES_EXTRA}; \
fi >> ${.TARGET}
${RUN} \
if ${_NONZERO_FILESIZE_P} ${_CHECK_FILES_MISSING_SKIP}; then \
${ECHO} "************************************************************"; \
${ECHO} "The following files are in both the" \
"PLIST and CHECK_FILES_SKIP:"; \
${SED} "s|^| |" ${_CHECK_FILES_MISSING_SKIP}; \
fi >> ${.TARGET}
# Check ${PKG_SYSCONFDIR} for files which are not in the PLIST and are
# also not copied into place by the INSTALL scripts.
#
${_CHECK_FILES_ERRMSG.sysconfdir}: \
${_CHECK_FILES_PRE.sysconfdir} \
${_CHECK_FILES_POST.sysconfdir}
${RUN} \
if ${CMP} -s ${_CHECK_FILES_PRE.sysconfdir} \
${_CHECK_FILES_POST.sysconfdir}; then \
${DO_NADA}; \
else \
${ECHO} "************************************************************"; \
${ECHO} "The package has modified ${PKG_SYSCONFDIR}" \
"contents directly!"; \
${ECHO} " The offending files/directories are:"; \
${DIFF} -u ${_CHECK_FILES_PRE.sysconfdir} \
${_CHECK_FILES_POST.sysconfdir} | \
${GREP} '^+[^+]' | ${SED} "s|^+| |"; \
fi > ${.TARGET}
# Check ${VARBASE} for files which are not in the PLIST and are also
# not created by the INSTALL scripts.
#
${_CHECK_FILES_ERRMSG.varbase}: \
${_CHECK_FILES_PRE.varbase} \
${_CHECK_FILES_POST.varbase}
${RUN} \
if ${CMP} -s ${_CHECK_FILES_PRE.varbase} \
${_CHECK_FILES_POST.varbase}; then \
${DO_NADA}; \
else \
${ECHO} "************************************************************"; \
${ECHO} "The package has modified ${VARBASE}" \
"contents directly!"; \
${ECHO} " The offending files/directories are:"; \
${DIFF} -u ${_CHECK_FILES_PRE.varbase} \
${_CHECK_FILES_POST.varbase} | \
${GREP} '^+[^+]' | ${SED} "s|^+| |"; \
fi > ${.TARGET}
###########################################################################
# check-files-clean removes the state files related to the "check-files"
# target so that the check-files-{pre,post} targets may be re-run.
#
.PHONY: check-files-clean
check-clean: check-files-clean
check-files-clean:
${RUN} \
${RM} -f ${_CHECK_FILES_ERRMSGS} \
${_CHECK_FILES_PRE} ${_CHECK_FILES_POST} \
${_CHECK_FILES_DIFF} ${_CHECK_FILES_ADDED} \
${_CHECK_FILES_DELETED} ${_CHECK_FILES_EXPECTED} \
${_CHECK_FILES_MISSING} ${_CHECK_FILES_MISSING_SKIP} \
${_CHECK_FILES_MISSING_REAL} ${_CHECK_FILES_EXTRA}