a)
ar x "${srcdir}/${x}" || die "$myfail"
;;
+ lzma)
+ if [ "${y}" == "tar" ]; then
+ lzma -dc "${srcdir}${x}" | tar xof - ${tar_opts}
+ assert "$myfail"
+ else
+ lzma -dc "${srcdir}${x}" > ${x%.*} || die "$myfail"
+ fi
+ ;;
*)
vecho "unpack ${x}: file format not recognized. Ignoring."
;;
"${PORTAGE_CONFIGROOT}"etc/etc-update.conf)
}
-scan() {
+diff_command() {
+ local cmd=${diff_command//%file1/$1}
+ ${cmd//%file2/$2}
+}
+scan() {
echo "Scanning Configuration files..."
rm -rf ${TMP}/files > /dev/null 2>&1
mkdir ${TMP}/files || die "Failed mkdir command!" 1
local find_opts
local my_basename
- # Sanity check to make sure diff exists and works
- if ! diff -v &>/dev/null ; then
- echo "ERROR: 'diff' does not seem to work, aborting"
- exit 1
- fi
-
for path in ${CONFIG_PROTECT} ; do
path="${EROOT}${path}"
find_opts="-iname ._cfg????_*"
for file in $(set -f; find ${path}/ ${find_opts} ! -iname '.*~' ! -iname '.*.bak' |
sed -e "s:\(^.*/\)\(\._cfg[0-9]*_\)\(.*$\):\1\2\3\%\2\%\3:" |
sort -t'%' -k3 -k2 | LANG=POSIX LC_ALL=POSIX cut -f1 -d'%'); do
+
rpath=$(echo "${file/\/\///}" | sed -e "s:/[^/]*$::")
rfile=$(echo "${file/\/\///}" | sed -e "s:^.*/::")
for mpath in ${CONFIG_PROTECT_MASK}; do
break
fi
done
- [ ! -f ${file} ] && continue
-
+ if [[ ! -f ${file} ]] ; then
+ echo "Skipping non-file ${file} ..."
+ continue
+ fi
if [[ "${ofile:10}" != "${rfile:10}" ]] ||
[[ ${opath} != ${rpath} ]]; then
elif [[ "${DELETE_ALL}" == "yes" ]] && ! user_special "${ofile}"; then
my_input=2
else
- showdiffcmd=$(echo "${diff_command}" |
- sed -e "s:%file1:${ofile}:" -e "s:%file2:${file}:")
-
if [ "${using_editor}" == 0 ]; then
(
echo "Showing differences between ${ofile} and ${file}"
- ${showdiffcmd}
+ diff_command "${ofile}" "${file}"
) | ${pager}
else
echo "Beginning of differences between ${ofile} and ${file}"
- ${showdiffcmd}
+ diff_command "${ofile}" "${file}"
echo "End of differences between ${ofile} and ${file}"
fi
if [ -L "${file}" ]; then
return 255
;;
2) ( echo "Showing differences between ${ofile} and ${mfile}"
- $(echo "${diff_command}" | \
- sed -e "s:%file1:${ofile}:" \
- -e "s:%file2:${mfile}:") ) | ${pager}
+ diff_command "${ofile}" "${mfile}" ) | ${pager}
continue
;;
3) break
exit ${2}
}
+usage() {
+ cat <<-EOF
+ etc-update: Handle configuration file updates
+
+ Usage: etc-update [options]
+
+ Options:
+ -d, --debug Enable shell debugging
+ -h, --help Show help and run away
+ -V, --version Show version and trundle away
+ EOF
+
+ [[ -n ${*:2} ]] && printf "\nError: %s\n" "${*:2}" 1>&2
+
+ exit ${1:-0}
+}
+
#
# Run the script
#
-scriptname=$(basename $0)
+
+SET_X=false
+while [[ -n $1 ]] ; do
+ case $1 in
+ -d|--debug) SET_X=true;;
+ -h|--help) usage;;
+ -V|--version) echo '$Id$'; exit 0;;
+ *) usage 1 "Invalid option '$1'";;
+ esac
+ shift
+done
+${SET_X} && set -x
type portageq > /dev/null || exit $?
eval $(portageq envvar -v CONFIG_PROTECT \
using_editor=$(get_config using_editor)
merge_command=$(get_config merge_command)
declare -i mode=$(get_config mode)
-[ -z ${mode} ] && mode=0
-[ -z "${pager}" ] && pager="cat"
+[[ -z ${mode} ]] && mode=0
+[[ -z ${pager} ]] && pager="cat"
+
+# Sanity check to make sure diff exists and works
+echo > "${TMP}"/.diff-test-1
+echo > "${TMP}"/.diff-test-2
+
+if ! diff_command "${TMP}"/.diff-test-1 "${TMP}"/.diff-test-2 &> /dev/null ; then
+ echo "ERROR: '${diff_command}' does not seem to work, aborting"
+ exit 1
+fi
#echo "rm_opts: $rm_opts, mv_opts: $mv_opts, cp_opts: $cp_opts"
#echo "pager: $pager, diff_command: $diff_command, merge_command: $merge_command"
[[ ${abort} == "yes" ]] && hasq stricter ${FEATURES} && die "poor code kills airplanes"
fi
+ # Compiled python objects do not belong in /usr/share (FHS violation)
+ # and can be a pain when upgrading python
+ f=$(find "${ED}"/usr/share -name '*.py[co]')
+ if [[ -n ${f} ]] ; then
+ vecho -ne '\a\n'
+ eqawarn "QA Notice: Precompiled python object files do not belong in /usr/share"
+ eqawarn "${f}"
+ vecho -ne '\a\n'
+ fi
+
# Portage regenerates this on the installed system.
rm -f "${ED}"/usr/share/info/dir{,.gz,.bz2}
print "!!! One of the following masked packages is required to complete your request:"
oldcomment = ""
shown_licenses = []
+ portdb_keys = ["LICENSE","SLOT"]
for p in alleb:
mreasons = portage.getmaskingstatus(p,
settings=pkgsettings, portdb=portdb)
print comment
oldcomment = comment
try:
- licenses = portdb.aux_get(p, ["LICENSE"])[0]
+ metadata = dict(izip(portdb_keys,
+ portdb.aux_get(p, portdb_keys)))
except KeyError:
# Corruption will have been reported above.
continue
- uselist = []
- if "?" in licenses:
+ metadata["USE"] = ""
+ if "?" in metadata["LICENSE"]:
pkgsettings.setcpv(p, mydb=portdb)
- uselist = pkgsettings.get("USE", "").split()
+ metadata["USE"] = pkgsettings.get("USE", "")
missing_licenses = []
try:
missing_licenses = \
pkgsettings.getMissingLicenses(
- licenses, p, uselist)
+ p, metadata)
except portage.exception.InvalidDependString:
# This will have already been reported
# above via mreasons.
if has_changed:
self.reset(keeping_pkg=1,use_cache=use_cache)
- def getMissingLicenses(self, licenses, cpv, uselist):
+ def getMissingLicenses(self, cpv, metadata):
"""
Take a LICENSE string and return a list any licenses that the user may
may need to accept for the given package. The returned list will not
contain any licenses that have already been accepted. This method
can throw an InvalidDependString exception.
- @param licenses: A raw LICENSE string as returned form dbapi.aux_get()
- @type licenses: String
@param cpv: The package name (for package.license support)
@type cpv: String
- @param uselist: A list of flags for evaluation of USE conditionals
- @type uselist: List
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
@rtype: List
@return: A list of licenses that have not been accepted.
"""
cpdict = self._plicensedict.get(dep_getkey(cpv), None)
if cpdict:
acceptable_licenses = self._accept_license.copy()
- for atom in match_to_list(cpv, cpdict.keys()):
+ cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
+ for atom in match_to_list(cpv_slot, cpdict.keys()):
acceptable_licenses.update(cpdict[atom])
- license_struct = portage.dep.paren_reduce(licenses)
+ license_struct = portage.dep.paren_reduce(metadata["LICENSE"])
license_struct = portage.dep.use_reduce(
- license_struct, uselist=uselist)
+ license_struct, uselist=metadata["USE"].split())
license_struct = portage.dep.dep_opconvert(license_struct)
return self._getMissingLicenses(license_struct, acceptable_licenses)
# keywords checking
try:
- mygroups, licenses, eapi = portdb.aux_get(
- mycpv, ["KEYWORDS", "LICENSE", "EAPI"])
+ eapi, mygroups, licenses, slot = portdb.aux_get(
+ mycpv, ["EAPI", "KEYWORDS", "LICENSE", "SLOT"])
except KeyError:
# The "depend" phase apparently failed for some reason. An associated
# error message will have already been printed to stderr.
if kmask:
rValue.append(kmask+" keyword")
- uselist = []
+ use = ""
if "?" in licenses:
settings.setcpv(mycpv, mydb=portdb)
- uselist = settings.get("USE", "").split()
+ use = settings.get("USE", "")
try:
missing_licenses = settings.getMissingLicenses(
- licenses, mycpv, uselist)
+ mycpv, {"LICENSE":licenses, "SLOT":slot, "USE":use})
if missing_licenses:
allowed_tokens = set(["||", "(", ")"])
allowed_tokens.update(missing_licenses)
import portage.xpak, portage.getbinpkg
import os, errno, stat
+from itertools import izip
class bindbapi(fakedbapi):
def __init__(self, mybintree=None, settings=None):
self.settings = settings
self._match_cache = {}
# Selectively cache metadata in order to optimize dep matching.
- self._aux_cache_keys = set(["CHOST","EAPI","SLOT","EPREFIX"])
+ self._aux_cache_keys = set(
+ ["CHOST", "EAPI", "KEYWORDS", "LICENSE", "SLOT", "EPREFIX"])
self._aux_cache = {}
def match(self, *pargs, **kwargs):
self.invalids = []
self.settings = settings
self._pkg_paths = {}
+ self._populating = False
self._all_directory = os.path.isdir(
os.path.join(self.pkgdir, "All"))
self._pkgindex_version = 0
self._pkgindex_hashes = ["MD5","SHA1"]
self._pkgindex_file = os.path.join(self.pkgdir, "Packages")
- self._pkgindex_keys = set(["CPV", "SLOT", "MTIME", "SIZE"])
+ self._pkgindex_keys = self.dbapi._aux_cache_keys.copy()
+ self._pkgindex_keys.update(["CPV", "MTIME", "SIZE"])
self._pkgindex_header_keys = set(["ACCEPT_KEYWORDS", "CBUILD",
"CHOST", "CONFIG_PROTECT", "CONFIG_PROTECT_MASK", "FEATURES",
"GENTOO_MIRRORS", "INSTALL_MASK", "SYNC", "USE"])
def populate(self, getbinpkgs=0, getbinpkgsonly=0):
"populates the binarytree"
+ if self._populating:
+ return
from portage.locks import lockfile, unlockfile
pkgindex_lock = None
try:
if os.access(self.pkgdir, os.W_OK):
pkgindex_lock = lockfile(self._pkgindex_file,
wantnewlockfile=1)
+ self._populating = True
self._populate(getbinpkgs, getbinpkgsonly)
finally:
if pkgindex_lock:
unlockfile(pkgindex_lock)
+ self._populating = False
def _populate(self, getbinpkgs=0, getbinpkgsonly=0):
if (not os.path.isdir(self.pkgdir) and not getbinpkgs):
if not getbinpkgsonly:
pkg_paths = {}
+ self._pkg_paths = pkg_paths
dirs = listdir(self.pkgdir, dirsonly=True, EmptyOnError=True)
if "All" in dirs:
dirs.remove("All")
d["SLOT"] = slot
d["MTIME"] = str(long(s.st_mtime))
d["SIZE"] = str(s.st_size)
+
+ aux_keys = list(self.dbapi._aux_cache_keys)
+ d.update(izip(aux_keys,
+ self.dbapi.aux_get(mycpv, aux_keys)))
+
# record location if it's non-default
if mypath != mycpv + ".tbz2":
d["PATH"] = mypath
aux_cache[k] = d[k]
self.dbapi._aux_cache[mycpv] = aux_cache
- self._pkg_paths = pkg_paths
# Do not bother to write the Packages index if $PKGDIR/All/ exists
# since it will provide no benefit due to the need to read CATEGORY
# from xpak.
stale = [cpv for cpv in metadata if cpv not in self._pkg_paths]
for cpv in stale:
del metadata[cpv]
+ #
+ self._update_pkgindex_header(pkgindex.header)
from portage.util import atomic_ofstream
f = atomic_ofstream(self._pkgindex_file)
try:
# record location if it's non-default
if rel_path != cpv + ".tbz2":
d["PATH"] = rel_path
- keys = ["USE", "IUSE", "DESCRIPTION", "LICENSE", "PROVIDE", \
+ keys = ["USE", "IUSE", "DESCRIPTION", "EAPI", "LICENSE", "PROVIDE", \
"RDEPEND", "DEPEND", "PDEPEND"]
from itertools import izip
d.update(izip(keys, self.dbapi.aux_get(cpv, keys)))
hasstable = True
if not match and ((hastesting and "~*" in pgroups) or (hasstable and "*" in pgroups) or "**" in pgroups):
match=1
- uselist = []
+ use = ""
if "?" in licenses:
self.doebuild_settings.setcpv(mycpv, mydb=self)
- uselist = self.doebuild_settings.get("USE", "").split()
+ use = self.doebuild_settings.get("USE", "")
try:
- if self.mysettings.getMissingLicenses(
- licenses, mycpv, uselist):
+ if self.mysettings.getMissingLicenses(mycpv,
+ {"LICENSE":licenses, "SLOT":slot, "USE":use}):
match = 0
except InvalidDependString:
match = 0
self.header.update(readpkgindex(pkgfile))
def readBody(self, pkgfile):
+ header_chost = self.header.get("CHOST")
while True:
d = readpkgindex(pkgfile)
if not d:
mycpv = d.get("CPV")
if not mycpv:
continue
+ d.setdefault("EAPI", "0")
d.setdefault("SLOT", "0")
+ if header_chost:
+ d.setdefault("CHOST", header_chost)
self.packages[mycpv] = d
def write(self, pkgfile):
keys = self.header.keys()
keys.sort()
writepkgindex(pkgfile, [(k, self.header[k]) for k in keys])
+ header_chost = self.header.get("CHOST")
for cpv in cpv_all:
metadata = self.packages[cpv].copy()
+ if metadata.get("CHOST") == header_chost:
+ del metadata["CHOST"]
+ if metadata.get("EAPI") == "0":
+ del metadata["EAPI"]
if metadata.get("SLOT") == "0":
del metadata["SLOT"]
if metadata.get("USE") == "":