Also adds support for uninstalling extensions. Legacy config is still compatible, but it is advised to migrate to latest config. Users are warned about this in logs. I find this pretty much ready, except I think about something down below. Latest Gnome extension version, that is compatible with Gnome version of the image, is installed by default. Legacy config format can be used to have this support, but I want to depreciate legacy config format in the future. So Idk If I should add this feature as an option in new config format. It can be useful in case of some extension regressions.
222 lines
11 KiB
Bash
222 lines
11 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# Tell build process to exit if there are any errors.
|
|
set -euo pipefail
|
|
|
|
get_yaml_array INSTALL '.install[]' "$1"
|
|
get_yaml_array UNINSTALL '.uninstall[]' "$1"
|
|
|
|
if [[ ${#INSTALL[@]} -lt 1 ]] && [[ ${#UNINSTALL[@]} -lt 1 ]]; then
|
|
echo "ERROR: You did not specify the extension to install or uninstall in module recipe file"
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v gnome-shell &> /dev/null; then
|
|
echo "ERROR: Your custom image is using non-Gnome desktop environment, where Gnome extensions are not supported"
|
|
exit 1
|
|
fi
|
|
|
|
GNOME_VER=$(gnome-shell --version | sed 's/[^0-9]*\([0-9]*\).*/\1/')
|
|
echo "Gnome version: ${GNOME_VER}"
|
|
LEGACY=false
|
|
|
|
# Legacy support for installing extensions, to retain compatibility with legacy configs
|
|
if [[ ${#INSTALL[@]} -gt 0 ]] then
|
|
for EXTENSION in "${INSTALL[@]}"; do
|
|
# If extension contains .v12 suffix at the end, than it's the legacy install entry
|
|
# 12 number in .v12 is just an example, any integer after it is allowed
|
|
shopt -s extglob
|
|
if [[ ! "${EXTENSION}" == *".v"*([0-9]) ]]; then
|
|
break
|
|
else
|
|
LEGACY=true
|
|
fi
|
|
shopt -u extglob
|
|
echo "ATTENTION: This is the legacy method of installing extensions."
|
|
echo " Change the install entry to literal name of the extension"
|
|
echo " Please see the latest docs of gnome-extensions module for more details:"
|
|
echo " https://blue-build.org/reference/modules/gnome-extensions/"
|
|
URL="https://extensions.gnome.org/extension-data/${EXTENSION}.shell-extension.zip"
|
|
TMP_DIR="/tmp/${EXTENSION}"
|
|
ARCHIVE=$(basename "${URL}")
|
|
ARCHIVE_DIR="${TMP_DIR}/${ARCHIVE}"
|
|
VERSION=$(echo "${EXTENSION}" | grep -oP 'v\d+')
|
|
echo "Installing ${EXTENSION} Gnome extension with version ${VERSION}"
|
|
# Download archive
|
|
wget --directory-prefix="${TMP_DIR}" "${URL}"
|
|
# Extract archive
|
|
echo "Extracting ZIP archive"
|
|
unzip "${ARCHIVE_DIR}" -d "${TMP_DIR}" > /dev/null
|
|
# Remove archive
|
|
echo "Removing archive"
|
|
rm "${ARCHIVE_DIR}"
|
|
# Read necessary info from metadata.json
|
|
echo "Reading necessary info from metadata.json"
|
|
EXTENSION_NAME=$(yq '.name' < "${TMP_DIR}/metadata.json")
|
|
UUID=$(yq '.uuid' < "${TMP_DIR}/metadata.json")
|
|
EXT_GNOME_VER=$(yq '.shell-version[]' < "${TMP_DIR}/metadata.json")
|
|
# If extension does not have the important key in metadata.json,
|
|
# inform the user & fail the build
|
|
if [[ "${UUID}" == "null" ]]; then
|
|
echo "ERROR: Extension '${EXTENSION_NAME}' doesn't have 'uuid' key inside metadata.json"
|
|
echo "You may inform the extension developer about this error, as he can fix it"
|
|
exit 1
|
|
fi
|
|
if [[ "${EXT_GNOME_VER}" == "null" ]]; then
|
|
echo "ERROR: Extension '${EXTENSION_NAME}' doesn't have 'shell-version' key inside metadata.json"
|
|
echo "You may inform the extension developer about this error, as he can fix it"
|
|
exit 1
|
|
fi
|
|
# Compare if extension is compatible with current Gnome version
|
|
# If extension is not compatible, inform the user & fail the build
|
|
if ! [[ "${EXT_GNOME_VER}" =~ "${GNOME_VER}" ]]; then
|
|
echo "ERROR: Extension '${EXTENSION_NAME}' is not compatible with current Gnome v${GNOME_VER}!"
|
|
exit 1
|
|
fi
|
|
# Install main extension files
|
|
echo "Installing main extension files"
|
|
install -d -m 0755 "/usr/share/gnome-shell/extensions/${UUID}/"
|
|
find "${TMP_DIR}" -mindepth 1 -maxdepth 1 ! -path "*locale*" ! -path "*schemas*" -exec cp -r {} "/usr/share/gnome-shell/extensions/${UUID}/" \;
|
|
find "/usr/share/gnome-shell/extensions/${UUID}" -type d -exec chmod 0755 {} +
|
|
find "/usr/share/gnome-shell/extensions/${UUID}" -type f -exec chmod 0644 {} +
|
|
# Install schema
|
|
if [[ -d "${TMP_DIR}/schemas" ]]; then
|
|
echo "Installing schema extension file"
|
|
install -d -m 0755 "/usr/share/glib-2.0/schemas/"
|
|
install -D -p -m 0644 "${TMP_DIR}/schemas/"*.gschema.xml "/usr/share/glib-2.0/schemas/"
|
|
fi
|
|
# Install languages
|
|
# Locale is not crucial for extensions to work, as they will fallback to gschema.xml
|
|
# Some of them might not have any locale at the moment
|
|
# So that's why I made a check for directory
|
|
if [[ -d "${TMP_DIR}/locale" ]]; then
|
|
echo "Installing language extension files"
|
|
install -d -m 0755 "/usr/share/locale/"
|
|
cp -r "${TMP_DIR}/locale"/* "/usr/share/locale/"
|
|
fi
|
|
# Delete the temporary directory
|
|
echo "Cleaning up the temporary directory"
|
|
rm -r "${TMP_DIR}"
|
|
echo "Extension '${EXTENSION_NAME}' is successfully installed"
|
|
echo "----------------------------------INSTALLATION DONE----------------------------------"
|
|
done
|
|
fi
|
|
|
|
# New method of installing extensions
|
|
if [[ ${#INSTALL[@]} -gt 0 ]] && ! "${LEGACY}"; then
|
|
for INSTALL_EXT in "${INSTALL[@]}"; do
|
|
# Replaces whitespaces with %20 for install entries which contain extension name, since URLs can't contain whitespace
|
|
WHITESPACE_HTML=$(echo "${INSTALL_EXT}" | sed 's/ /%20/g')
|
|
URL_QUERY=$(curl -s "https://extensions.gnome.org/extension-query/?search=${WHITESPACE_HTML}")
|
|
QUERIED_EXT=$(echo "${URL_QUERY}" | yq ".extensions[] | select(.name == \"${INSTALL_EXT}\")")
|
|
if [[ -z "${QUERIED_EXT}" ]]; then
|
|
echo "ERROR: Extension '${INSTALL_EXT}' does not exist in https://extensions.gnome.org/ website"
|
|
echo " Extension name is case-sensitive, so be sure that you typed it correctly,"
|
|
echo " including the correct uppercase & lowercase characters"
|
|
exit 1
|
|
fi
|
|
EXT_UUID=$(echo "${QUERIED_EXT}" | yq ".uuid")
|
|
EXT_NAME=$(echo "${QUERIED_EXT}" | yq ".name")
|
|
# Gets suitable extension version for Gnome version from the image
|
|
SUITABLE_VERSION=$(echo "${QUERIED_EXT}" | yq ".shell_version_map[${GNOME_VER}].version")
|
|
if [[ "${SUITABLE_VERSION}" == "null" ]]; then
|
|
echo "ERROR: Extension '${EXT_NAME}' is not compatible with Gnome v${GNOME_VER} in your image"
|
|
exit 1
|
|
fi
|
|
# Removes every @ symbol from UUID, since extension URL doesn't contain @ symbol
|
|
URL="https://extensions.gnome.org/extension-data/${EXT_UUID//@/}.v${SUITABLE_VERSION}.shell-extension.zip"
|
|
TMP_DIR="/tmp/${EXT_UUID}"
|
|
ARCHIVE=$(basename "${URL}")
|
|
ARCHIVE_DIR="${TMP_DIR}/${ARCHIVE}"
|
|
echo "Installing '${EXT_NAME}' Gnome extension with version ${SUITABLE_VERSION}"
|
|
# Download archive
|
|
wget --directory-prefix="${TMP_DIR}" "${URL}"
|
|
# Extract archive
|
|
echo "Extracting ZIP archive"
|
|
unzip "${ARCHIVE_DIR}" -d "${TMP_DIR}" > /dev/null
|
|
# Remove archive
|
|
echo "Removing archive"
|
|
rm "${ARCHIVE_DIR}"
|
|
# Install main extension files
|
|
echo "Installing main extension files"
|
|
install -d -m 0755 "/usr/share/gnome-shell/extensions/${EXT_UUID}/"
|
|
find "${TMP_DIR}" -mindepth 1 -maxdepth 1 ! -path "*locale*" ! -path "*schemas*" -exec cp -r {} "/usr/share/gnome-shell/extensions/${EXT_UUID}/" \;
|
|
find "/usr/share/gnome-shell/extensions/${EXT_UUID}" -type d -exec chmod 0755 {} +
|
|
find "/usr/share/gnome-shell/extensions/${EXT_UUID}" -type f -exec chmod 0644 {} +
|
|
# Install schema
|
|
if [[ -d "${TMP_DIR}/schemas" ]]; then
|
|
echo "Installing schema extension file"
|
|
install -d -m 0755 "/usr/share/glib-2.0/schemas/"
|
|
install -D -p -m 0644 "${TMP_DIR}/schemas/"*.gschema.xml "/usr/share/glib-2.0/schemas/"
|
|
fi
|
|
# Install languages
|
|
# Locale is not crucial for extensions to work, as they will fallback to gschema.xml
|
|
# Some of them might not have any locale at the moment
|
|
# So that's why I made a check for directory
|
|
if [[ -d "${TMP_DIR}/locale" ]]; then
|
|
echo "Installing language extension files"
|
|
install -d -m 0755 "/usr/share/locale/"
|
|
cp -r "${TMP_DIR}/locale"/* "/usr/share/locale/"
|
|
fi
|
|
# Delete the temporary directory
|
|
echo "Cleaning up the temporary directory"
|
|
rm -r "${TMP_DIR}"
|
|
echo "Extension '${EXT_NAME}' is successfully installed"
|
|
echo "----------------------------------INSTALLATION DONE----------------------------------"
|
|
done
|
|
fi
|
|
|
|
# Uninstall section goes here
|
|
if [[ ${#UNINSTALL[@]} -gt 0 ]]; then
|
|
for UNINSTALL_EXT in "${UNINSTALL[@]}"; do
|
|
# Replaces whitespaces with %20 for install entries which contain extension name, since URLs can't contain whitespace
|
|
# Getting json query from the website is useful to intuitively uninstall the extension without need to manually input UUID
|
|
WHITESPACE_HTML=$(echo "${UNINSTALL_EXT}" | sed 's/ /%20/g')
|
|
URL_QUERY=$(curl -s "https://extensions.gnome.org/extension-query/?search=${WHITESPACE_HTML}")
|
|
QUERIED_EXT=$(echo "${URL_QUERY}" | yq ".extensions[] | select(.name == \"${UNINSTALL_EXT}\")")
|
|
if [[ -z "${QUERIED_EXT}" ]]; then
|
|
echo "ERROR: Extension '${UNINSTALL_EXT}' does not exist in https://extensions.gnome.org/ website"
|
|
echo " Extension name is case-sensitive, so be sure that you typed it correctly,"
|
|
echo " including the correct uppercase & lowercase characters"
|
|
exit 1
|
|
fi
|
|
EXT_UUID=$(echo "${QUERIED_EXT}" | yq ".uuid")
|
|
EXT_NAME=$(echo "${QUERIED_EXT}" | yq ".name")
|
|
# This is where uninstall step goes, above step is reused from install part
|
|
EXT_FILES="/usr/share/gnome-shell/extensions/${EXT_UUID}"
|
|
UNINSTALL_METADATA="${EXT_FILES}/metadata.json"
|
|
GETTEXT_DOMAIN=$(yq -I=0 ".gettext-domain" < "${UNINSTALL_METADATA}")
|
|
SETTINGS_SCHEMA=$(yq -I=0 ".settings-schema" < "${UNINSTALL_METADATA}")
|
|
LANGUAGE_LOCATION="/usr/share/locale"
|
|
# If settings-schema YAML key exists, than use that, if it doesn't
|
|
# Than substract the schema ID before @ symbol
|
|
if [[ ! "${SETTINGS_SCHEMA}" == "null" ]]; then
|
|
SCHEMA_LOCATION="/usr/share/glib-2.0/schemas/${SETTINGS_SCHEMA}.gschema.xml"
|
|
else
|
|
SUBSTRACTED_UUID=$(echo "${EXT_UUID}" | cut -d'@' -f1)
|
|
SCHEMA_LOCATION="/usr/share/glib-2.0/schemas/org.gnome.shell.extensions.${SUBSTRACTED_UUID}.gschema.xml"
|
|
fi
|
|
# Remove languages
|
|
if [[ ! "${GETTEXT_DOMAIN}" == "null" ]]; then
|
|
find "${LANGUAGE_LOCATION}" -type f -name "${GETTEXT_DOMAIN}.mo" -exec rm {} \;
|
|
else
|
|
echo "There are no extension languages to remove, since extension doesn't contain them"
|
|
fi
|
|
# Remove gschema xml
|
|
if [[ ! "${SETTINGS_SCHEMA}" == "null" ]] && [[ -f "${SCHEMA_LOCATION}" ]]; then
|
|
rm "${SCHEMA_LOCATION}"
|
|
else
|
|
echo "There is no gschema xml to remove, since extension doesn't have any settings"
|
|
fi
|
|
# Removing main extension files
|
|
echo "Removing main extension files"
|
|
rm -r "${EXT_FILES}"
|
|
echo "----------------------------------UNINSTALLATION DONE----------------------------------"
|
|
done
|
|
fi
|
|
|
|
# Compile gschema to include schemas from extensions & to refresh schema state after uninstall is done
|
|
echo "Compiling gschema to include extension schemas & to refresh the schema state"
|
|
glib-compile-schemas "/usr/share/glib-2.0/schemas/" &>/dev/null
|
|
|
|
echo "Finished the setup of gnome-extensions module"
|