# -*-eselect-*- vim: ft=eselect # Copyright 2005-2017 Gentoo Foundation # Distributed under the terms of the GNU GPL version 2 or later inherit config multilib tests DESCRIPTION="Manage active wine version" MAINTAINER="NP-Hardass@gentoo.org" CONFIG_DIR="/etc/eselect/wine" VARIANTS=( vanilla staging d3d9 any ) ################################################################################ # Eselect Wine # ################################################################################ # Verify that files exist for specified target # Input: ${P} is_valid_target(){ if [[ $# -ne 1 ]]; then die "Invalid number of parameters" fi local tgt="$1" set_dir_env if [[ ! -d "${wine_bin}" ]] || \ [[ ! "$(ls -A ${wine_bin})" ]] || \ [[ ! -e "${wine_bin}/wine" ]]; then return 1 elif [[ ! -e "${EPREFIX}/usr/bin/${tgt}" ]]; then return 1 else return 0 fi unset_dir_env } # Verify that symlinks are valid are_symlinks_valid() { if [[ $# -gt 1 ]]; then die "Invalid number of parameters" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die "Invalid variant" fi else die "Invalid parameter" fi shift done local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi local active=$(get_active ${v_arg}) local tgt="${active}" if [[ "${active}" == "(unset)" ]]; then write_error_message "Invalid active config" return 1 fi set_dir_env local possible_vars=( bin man ) local symlink_vars=$(load_config "${CONFIG_DIR}/links/${v}" symlink_dirs) if [[ -z "${symlink_vars}" ]]; then die -q "Missing any configured symlink_dirs" fi local var for var in ${possible_vars[@]}; do if has ${var} ${symlink_vars[@]}; then symlink_vars=$(list_rm_item "${var}" "${symlink_vars}") else write_warning_message "Missing '${var}' in ${v} config" write_warning_message "Might want to re-run set or update" fi done if [[ ! -z ${symlink_vars} ]]; then die -q "Config contains unknown symlink_dirs ${symlink_vars}" fi symlink_vars=$(load_config "${CONFIG_DIR}/links/${v}" symlink_dirs) for var in ${symlink_vars[@]}; do local symlinks=$(load_config "${CONFIG_DIR}/links/${v}" ${var}) local symlink if [[ -z "${symlinks}" ]]; then die -q "Missing listing of ${var} symlinks" fi for symlink in ${symlinks[@]}; do if [[ ! -L ${symlink} ]]; then die -q "${symlink} is not a symlink" else local file=$(canonicalise ${symlink}) if [[ ! -e "${file}" ]]; then die -q "${symlink} points to nonexistant ${file}" # Handle bin separately because symlinks don't go to wine_${var} elif [[ "${var}" == "bin" ]]; then local path="${symlink%${v_arg#-}}${tgt#wine}" if [[ "${file}" != "${path}" ]]; then write_error_msg "${symlink} points to ${file}" write_error_msg "${path}" die -q "which doesn't appear to be the proper link" fi else local path=wine_${var} path=${!path} path=$(canonicalise "${path}") if [[ "${file}" != "${path%/}"/* ]]; then write_error_msg "${symlink} points to ${file}" die -q "which doesn't appear to be part of wine" fi fi fi done done unset_dir_env } # print currently selected wine get_active() { if [[ $# -gt 1 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die -q "Invalid variant" fi else [[ -z $1 ]] || die -q "Invalid parameter" fi shift done local active=$(load_config "${CONFIG_DIR}/active" ${v}) if [[ -z "${active}" ]]; then echo "(unset)" else echo "${active}" fi } get_installed(){ if [[ $# -gt 1 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die -q "Invalid variant" fi else die -q "Invalid parameter" fi shift done local installed=$(load_config "${CONFIG_DIR}/installed" ${v}) echo $(sort_list ${installed[@]}) } ### Registration action ## describe_register(){ echo "Register a new package with the eselect module (Internal use only)" } describe_register_parameters() { echo "" } describe_register_options() { for v in ${VARIANTS[@]}; do echo "--${v} : Register a new package with ${v}" done echo "target : A fully qualified variant e.g." echo " : wine-1.9.23, wine-vanilla-2.0, or wine-staging-2.1.1" } do_register(){ if [[ $# -lt 1 ]] || [[ $# -gt 3 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die -q "Invalid flag or variant" fi else local tgt="$1" fi shift done if [[ -z "${tgt}" ]]; then die -q "Target not specified" fi local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi if is_number "${tgt}"; then local tgts=($(get_installed ${v_arg})) tgt=${tgts[${tgt}-1]} fi if ! is_valid_target "${tgt}"; then die -q "Target does not exist" fi local list=$(get_installed ${v_arg}) if ! has ${tgt} ${list}; then list=($(sort_list "${list} ${tgt}")) store_config "${CONFIG_DIR}/installed" ${v} "${list[@]}" fi } describe_deregister(){ echo "Deregister a package with the eselect module (Internal use only)" } describe_deregister_parameters() { echo "" } describe_deregister_options() { for v in ${VARIANTS[@]}; do echo "--${v} : Deregister a package with ${v}" done echo "--force : Forcibly remove a package" echo "target : A fully qualified variant e.g." echo " : wine-1.9.23, wine-vanilla-2.0, or wine-staging-2.1.1" } do_deregister(){ if [[ $# -lt 1 ]] || [[ $# -gt 3 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" local force=false while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} elif [[ "${flag}" == "force" ]]; then force=true else die -q "Invalid variant" fi else local tgt="$1" fi shift done if [[ -z "${tgt}" ]]; then die -q "Target not specified" fi local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi if is_number "${tgt}"; then local tgts=($(get_installed ${v_arg})) tgt=${tgts[${tgt}-1]} fi if ! is_valid_target "${tgt}" && [[ ${force} == "false" ]]; then die -q "Target does not exist" fi local list=$(get_installed ${v_arg}) if ! has ${tgt} ${list}; then die -q "${tgt} is not registered for ${v}" fi if [[ "${tgt}" == "$(get_active ${v_arg})" ]]; then do_unset ${v_arg} fi list=$(list_rm_item ${tgt} "${list}") store_config "${CONFIG_DIR}/installed" ${v} "${list}" } ### list action ### describe_list() { echo "List available wine versions" } describe_list_options() { for v in ${VARIANTS[@]}; do echo "--${v} : List the available 'wine-${v}'" done } do_list() { if [[ $# -gt 1 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die -q "Invalid variant" fi else die -q "Invalid parameter" fi shift done local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi write_list_start "Available wine${v_arg#-} versions:" local installed=($(get_installed ${v_arg})) local active=$(get_active ${v_arg}) if [[ ${#installed} -eq 0 ]]; then unset installed else for (( i = 0; i < ${#installed[@]}; i++ )); do if [[ ${installed[i]} = ${active} ]]; then installed[i]=$(highlight_marker "${installed[i]}") fi done fi write_numbered_list -m "(none found)" "${installed[@]}" } ### show action ### describe_show() { echo "Show the active wine version" } describe_show_options() { for v in ${VARIANTS[@]}; do echo "--$v : Show the active 'wine-$v'" done } do_show() { if [[ $# -gt 1 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die -q "Invalid variant" fi else die -q "Invalid parameter" fi shift done local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi write_list_start "Active wine${v_arg#-} version:" local active=$(get_active ${v_arg}) write_kv_list_entry "${active}" "" if [[ "${active}" != "(unset)" ]]; then are_symlinks_valid ${v_arg} fi } ### unset action ### describe_unset() { echo "Remove wine symlinks" } describe_unset_options() { for v in ${VARIANTS[@]}; do echo "--$v : Remove the 'wine-$v' symlinks" done echo "--all : Unset active wine and all variants" } do_unset() { if [[ $# -gt 1 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" local all=false while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} elif [[ "${flag}" == "all" ]]; then all=true else die -q "Invalid variant" fi else die -q "Invalid parameter" fi shift done # Run do_unset for all variants if ${all}; then do_unset for v in ${VARIANTS[@]}; do do_unset "--${v}" done return 0 fi local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi remove_symlinks ${v_arg} || die -q "Couldn't remove wine${v_arg#-} symlinks" store_config "${CONFIG_DIR}/active" "${v}" "" } ### set action ### describe_set() { echo "Set a new wine version" } describe_set_parameters() { echo "" } describe_set_options() { for v in ${VARIANTS[@]}; do echo "--$v : Set only the 'wine-$v' symlinks" done echo "target : Target name or number (from 'list' action)" } do_set() { if [[ $# -lt 1 ]] || [[ $# -gt 2 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die -q "Invalid flag or variant" fi else local tgt="$1" fi shift done if [[ -z "${tgt}" ]]; then die -q "Target not specified" fi local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi if is_number "${tgt}"; then local tgts=($(get_installed ${v_arg})) tgt=${tgts[${tgt}-1]} fi if ! is_valid_target "${tgt}"; then die -q "Target does not exist" fi do_unset ${v_arg} || die -q "Failed to unset active target" set_symlinks ${v_arg} "${tgt}" || die -q "Couldn't set wine-${v_arg#-} symlinks" store_config "${CONFIG_DIR}/active" "${v}" "${tgt}" } ### update action ### describe_update() { echo "Set highest version installed active" } describe_update_options() { for v in ${VARIANTS[@]}; do echo "--$v : Update the 'wine-$v' symlinks" done echo "--all : Update main active wine and all variants" echo "--if-unset : Reuse currently selected version if it appears valid" } do_update() { if [[ $# -gt 3 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" local if_unset=false local all=false while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} elif [[ "${flag}" == "if-unset" ]]; then if_unset=true elif [[ "${flag}" == "all" ]]; then all=true else die -q "Invalid flag or variant" fi else die -q "Invalid parameter" fi shift done if [[ "${v}" != "wine" ]] && ${all}; then die -q "Either specify a specific variant, or all, but not both" fi # Run do_update for all variants if ${all}; then local unset_arg if ${if_unset}; then unset_arg="--if-unset" fi do_update ${unset_arg} for v in ${VARIANTS[@]}; do do_update "--${v}" ${unset_arg} done return 0 fi local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi # Determine if set and valid # If so, return if ${if_unset}; then local active=$(get_active ${v_arg}) if is_valid_target "${active}" && are_symlinks_valid ${v_arg}; then return 0 fi fi local installed=($(get_installed ${v_arg})) if [[ ${#installed[@]} -eq 0 ]]; then write_warning_msg "Skipping wine${v_arg#-}. No registered targets found." return 0 fi local tgt=${installed[-1]} do_set ${v_arg} "${tgt}" || die -q "Couldn't set new wine${v_arg#-} symlinks" } # lifted from fdo-mime.eclass desktop_database_update() { if [[ -x "${EPREFIX}/usr/bin/update-desktop-database" ]]; then # echo "Updating desktop mime database ..." "${EPREFIX}/usr/bin/update-desktop-database" -q "${EPREFIX}/usr/share/applications" || die fi } # sort function for versions, to be used in a pipe sort_versions() { local vsort="sort --version-sort" # Test if our sort supports the --version-sort option (posix does) ${vsort} /dev/null || vsort=sort # We sort versions as follows: # 1. Run sed to prepend the version string by the numeric version # 1.7.21 wine-1.7.21 # 1.7.14 wine-compholio-1.7.14 # 2. sort --version-sort # 3. Run sed again to remove the prepended keys from step 1. sed -e 's/^\(.\+-\)\([[:digit:].]*\)$/\2 &/' \ | LC_ALL=C ${vsort} | sed 's/.* //' } # Takes a list of items and returns a sorted version sort_list() { list=($@) if [[ ! -z "${list}" ]]; then for i in ${list[@]}; do echo "${i}" done | sort_versions fi } # Returns a list excluding the specified item # list_rm_item [rm_this] [list] list_rm_item() { if [[ $# -lt 2 ]]; then die "Not enough arguments" fi rm_this=$1 shift list=($@) local i for i in ${!list[@]};do if [ "${list[$i]}" == "${rm_this}" ]; then unset list[$i] fi done echo ${list[@]} } remove_symlinks() { if [[ $# -gt 1 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die -q "Invalid flag or variant" fi else die -q "Invalid parameter" fi shift done local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi local symlink_vars=$(load_config "${CONFIG_DIR}/links/${v}" symlink_dirs) if [[ -z "${symlink_vars}" ]]; then return 0 fi local var for var in ${symlink_vars[@]}; do local symlinks=$(load_config "${CONFIG_DIR}/links/${v}" ${var}) local symlink if [[ -z "${symlinks}" ]]; then die -q "Missing listing of ${var} symlinks" fi for symlink in ${symlinks[@]}; do if [[ -e "${symlink}" ]]; then if [[ ! -L "${symlink}" ]]; then die -q "${symlink} is not a symlink." fi rm "${symlink}" || die "Failed to rm ${symlink}" else write_warning_msg "${symlink} symlink was missing." fi # remove entry from config file symlinks=$(list_rm_item "${symlink}" "${symlinks}") done store_config "${CONFIG_DIR}/links/${v}" ${var} "${symlinks}" # remove set from config file symlink_vars=$(list_rm_item "${var}" "${symlink_vars}") store_config "${CONFIG_DIR}/links/${v}" symlink_dirs "${symlink_vars}" done # Remove active if it exists store_config "${CONFIG_DIR}/active" "${v}" "" local desktop="${EPREFIX}/usr/share/applications/wine${v_arg#-}.desktop" if [[ -e "${desktop}" ]]; then rm "${desktop}" || die "Failed ro remove desktop file" fi desktop_database_update || die "Failed to update xorg desktop database" } set_symlinks() { if [[ $# -lt 1 ]] || [[ $# -gt 2 ]]; then die -q "Invalid number of parameters specified" fi local v="wine" while [[ $# -gt 0 ]]; do if [[ $1 == --* ]]; then local flag="${1#--}" if has "${flag}" ${VARIANTS[@]}; then v=${flag} else die -q "Invalid flag or variant" fi else local tgt="$1" fi shift done if [[ -z "${tgt}" ]]; then die -q "Target not specified" fi local v_arg if [[ ${v} != "wine" ]]; then v_arg="--${v}" fi if is_number "${tgt}"; then local tgts=($(get_installed ${v_arg})) tgt=${tgts[${tgt}-1]} fi if ! is_valid_target "${tgt}"; then die -q "Target does not exist" fi set_dir_env local link local links store_config "${CONFIG_DIR}/links/${v}" symlink_dirs "bin" store_config "${CONFIG_DIR}/links/${v}" "bin" "" for b in "${wine_bin}"/*; do link="${EPREFIX}/usr/bin/${b##*/}${v_arg#-}" local linktgt="${EPREFIX}/usr/bin/${b##*/}${tgt##wine}" ln -s "${linktgt}" "${link}" if [[ $? -ne 0 ]]; then write_warning_msg "Failed to set symlink from ${linktgt} to ${link}" write_warning_msg "Cleaning up" remove_symlinks ${v_arg} fi links="${links} ${link}" done store_config "${CONFIG_DIR}/links/${v}" "bin" "${links}" links="" append_config "${CONFIG_DIR}/links/${v}" symlink_dirs "man" store_config "${CONFIG_DIR}/links/${v}" "man" "" for md in "${wine_man}"/*; do for m in "${md}"/*; do link="${EPREFIX}/usr/share/man/${md##*/}/${m##*/}${v_arg#-}" ln -s "${m}" "${link}" if [[ $? -ne 0 ]]; then write_warning_msg "Failed to set symlink from ${m} to ${link}" write_warning_msg "Cleaning up" remove_symlinks ${v_arg} fi links="${links} ${link}" done done append_config "${CONFIG_DIR}/links/${v}" "man" "${links}" local desktop="${EPREFIX}/usr/share/applications/wine${v_arg#-}.desktop" cp "${wine_app}/wine.desktop" "${desktop}" || die "Failed to copy desktop file" sed -i "s:Exec=.*:Exec=wine${v_arg#-} start /unix %f:" ${desktop} || die "Failed to edit desktop file" desktop_database_update || die "Failed to update xorg desktop database" unset_dir_env } # set env vars for us to work with set_dir_env() { wine_bin="${EPREFIX}/usr/lib/${tgt}/bin" wine_include="${EPREFIX}/usr/include/${tgt}/wine" wine_share="${EPREFIX}/usr/share/${tgt}" wine_app="${wine_share}/applications" wine_man="${wine_share}/man" } # unset our env vars unset_dir_env() { unset wine_{bin,include,share,app,man} }