app-eselect/eselect-swift: add 1.0-r1

Adds support for 'show --latest' to get the latest available version of
Swift on the system.

Signed-off-by: Itai Ferber <itai@itaiferber.net>
This commit is contained in:
Itai Ferber 2025-03-25 20:28:54 -04:00
parent 0cf9b38183
commit 92283709cc
No known key found for this signature in database
GPG Key ID: 39E67F4ECE95ED64
2 changed files with 313 additions and 0 deletions

View File

@ -0,0 +1,24 @@
# Copyright 1999-2025 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
EAPI=8
DESCRIPTION="Manages Swift symlinks"
HOMEPAGE="https://wiki.gentoo.org/wiki/No_homepage"
S="${WORKDIR}"
LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~amd64"
RDEPEND="app-admin/eselect"
src_install() {
insinto /usr/share/eselect/modules
newins "${FILESDIR}/swift-${PVR}.eselect" swift.eselect || die
}
pkg_postinst() {
eselect swift update
}

View File

@ -0,0 +1,289 @@
# -*-eselect-*- vim: ft=eselect
# Copyright 2005-2025 Gentoo Authors
# Distributed under the terms of the GNU GPL version 2 or later
DESCRIPTION="Manage the Swift symlink"
MAINTAINER="itai@itaiferber.net"
VERSION="1.0"
inherit path-manipulation
BIN_DIR="${EROOT%/}/usr/bin"
### Utility Functions ###
# @FUNCTION: get_index
# @USAGE: <element> <elements>...
# @DESCRIPTION:
# Returns the index of an element in an array, or the empty string if the
# element was not found.
get_index() {
local element="$1"
shift
local i elements=( "$@" )
for i in "${!elements[@]}"; do
if [[ "${elements[i]}" = "${element}" ]]; then
echo "${i}"
return 0
fi
done
return 1
}
# @FUNCTION: sort_swift_targets
# @USAGE: <target identifier>...
# @DESCRIPTION:
# Lexicographically sorts an array of Swift target identifiers.
sort_swift_targets() {
# `sort` may not support '--version-sort', so fall back on error
local vsort="sort --version-sort"
${vsort} </dev/null &>/dev/null || vsort="sort"
# Stolen from `app-eselect/eselect-luajit`: to handle potential `_beta`
# version suffixes, we:
# 1. Turn `swift-x.y.z` into `x.y.z 1 swift-x.y.z`
# 2. Turn `swift-x.y.z_beta...` into `x.y.z 0 swift-x.y.z_beta...`
# 3. Sort, which moves `_beta` versions before corresponding non-beta
# versions
# 4. Remove leading trivia
printf "%s\n" "$@" \
| sed -e 's/^\(swift-\)\?\([[:digit:].]\+\)[-_]beta/\2 0 &/' \
-e 't;s/^\(swift-\)\?\([[:digit:].]\+\)/\2 1 &/' \
| LC_ALL=C ${vsort} \
| sed 's/.* //'
}
# @FUNCTION: list_targets
# @DESCRIPTION:
# Returns a lexicographically-sorted list of Swift targets found in `BIN_DIR`.
list_targets() {
local identifiers
mapfile -t identifiers < <(find "${BIN_DIR}" -maxdepth 1 -type l -iname 'swift-[[:digit:]]*' -exec basename '{}' ';')
sort_swift_targets "${identifiers[@]}"
}
# @FUNCTION: list_target_links
# @USAGE: <target identifier>
# @DESCRIPTION:
# Given a Swift target identifier, lists all of the symlinks found in `BIN_DIR`
# that correspond to that Swift target.
list_target_links() {
local target="$1"
local version_number="${target#swift-}"
local swift_dir="$(dirname "$(canonicalise "${BIN_DIR}/${target}")")"
local files
mapfile -t files < <(find "${BIN_DIR}" -maxdepth 1 -type l -iname "*-${version_number}")
for f in "${files[@]}"; do
local d="$(dirname "$(canonicalise "${f}")")"
if [[ "${d}" == "${swift_dir}"* ]]; then
echo "${f}"
fi
done
}
# @FUNCTION: current_target_index
# @USAGE: <target identifier>...
# @DESCRIPTION:
# Returns the index of the currently-set target from the given list of available
# Swift targets. If `/usr/bin/swift` does not point to any of the given Swift
# targets, returns an empty string.
current_target_index() {
local t canonical_targets=()
for t in "$@"; do
canonical_targets+=("$(canonicalise "${BIN_DIR}/${t}")")
done
local canonical_swift_path="$(canonicalise "${BIN_DIR}/swift")"
get_index "${canonical_swift_path}" "${canonical_targets[@]}"
}
# @FUNCTION: current_target
# @USAGE: <target identifier>...
# @DESCRIPTION:
# Returns the target identifier of the currently-set target from the given list
# of available Swift targets. If `/usr/bin/swift` does not point to any of the
# given Swift targets, returns an empty string.
current_target() {
local targets=( "$@" )
local target="$(current_target_index "${targets[@]}")"
if is_number "${target}"; then
echo "${targets[target]}"
else
return 1
fi
}
# @FUNCTION: unset_target
# @USAGE: <target identifier>
# @DESCRIPTION:
# Unsets any unversioned links in `BIN_DIR` if they point to the given Swift
# target identifier.
unset_target() {
local target="$1"
local version_number="${target#swift-}"
local links
mapfile -t links < <(list_target_links "${target}")
local link
for link in "${links[@]}"; do
local unversioned_link="${link%-"${version_number}"}"
if [[ "$(canonicalise "${link}")" = "$(canonicalise "${unversioned_link}")" ]]; then
rm "${unversioned_link}" || die -q "Couldn't remove symlink '${unversioned_link}'"
fi
done
}
# @FUNCTION: set_target
# @USAGE: <target identifier> <target identifiers>...
# @DESCRIPTION:
# Unsets the current Swift target and sets unversioned symlinks in `BIN_DIR` for
# the given Swift target identifier. Does nothing if the given target identifier
# is the same as the current target identifier.
set_target() {
local target="$1"
shift
local current_target="$(current_target "$@")"
if [[ "${target}" = "${current_target}" ]]; then
return
fi
unset_target "${current_target}"
local version_number="${target#swift-}"
local links
mapfile -t links < <(list_target_links "${target}")
local link
for link in "${links[@]}"; do
local unversioned_link="${link%-"${version_number}"}"
ln -fs "${link}" "${unversioned_link}" || die -q "Couldn't create symlink '${unversioned_link}'"
done
}
### List Action ###
describe_list() {
echo "Lists available Swift versions"
}
do_list() {
local targets
mapfile -t targets < <(list_targets)
if [[ -n "${targets}" ]]; then
local current_target="$(current_target_index "${targets[@]}")"
if is_number "${current_target}"; then
targets[current_target]="$(highlight_marker "${targets[current_target]}")"
fi
write_list_start "Available Swift versions:"
write_numbered_list "${targets[@]}"
else
write_list_start "No available Swift versions"
fi
}
### Show Action ###
describe_show() {
echo "Show the current Swift implementation"
}
describe_show_options() {
echo "--latest : Show the latest available Swift implementation"
}
do_show() {
local show_latest=false
if [[ $# -gt 0 && "$1" = "--latest" ]]; then
show_latest=true
shift
fi
[[ $# -eq 0 ]] || die "'show' takes only '--latest' as a parameter"
local targets
mapfile -t targets < <(list_targets)
if [[ -z "${targets[@]}" ]]; then
write_list_start "No available Swift versions"
elif [[ "${show_latest}" = 'true' ]]; then
write_list_start "Latest Swift implementation:"
write_kv_list_entry "${targets[-1]}"
else
write_list_start "Current Swift implementation:"
local target="$(current_target "${targets[@]}")"
write_kv_list_entry "${target:-(unset)}"
fi
}
### Set Action ###
describe_set() {
echo "Set active Swift version"
}
describe_set_parameters() {
echo "<target>"
}
describe_set_options() {
echo "target : Target number or name (from 'list')"
}
do_set() {
[[ $# -eq 0 || -z "$1" ]] && die -q "No Swift version specified"
[[ $# -gt 1 ]] && die -q "'set' takes only one parameter"
local targets
mapfile -t targets < <(list_targets)
local target="$1"
if is_number "${target}"; then
[[ "$target" -gt 0 && "$1" -le "${#targets[@]}" ]] || die -q "'$1' is not a valid target"
target="${targets[target-1]}"
else
target_index="$(get_index "$1" "${targets[@]}")"
is_number "${target_index}" || die -q "'$1' is not a valid target"
fi
set_target "${target}" "${targets[@]}"
}
### Unset Action ###
describe_unset() {
echo "Unsets any active Swift version"
}
do_unset() {
[[ $# -eq 0 ]] || die -q "'unset' does not take any parameters"
local targets
mapfile -t targets < <(list_targets)
local target="$(current_target "${targets[@]}")"
unset_target "${target}"
}
### Update Action ###
describe_update() {
echo "Switch to the most recent Swift version"
}
do_update() {
[[ $# -eq 0 ]] || die -q "'update' does not take any parameters"
local targets
mapfile -t targets < <(list_targets)
[[ "${#targets[@]}" -gt 0 ]] || die -q "No Swift versions found"
local target="$(current_target "${targets[@]}")"
if [[ -n "${target}" ]]; then
unset_target "${target}"
fi
local new_target="${targets[-1]}"
set_target "${new_target}" "${targets[@]}"
}