#!/bin/bash # This is WPS Office build script for Porteus # Version 2026-08-27 # Copyright 2023-2030, Blaze, Dankov, Russia # All rights reserved. # # Redistribution and use of this script, with or without modification, is # permitted provided that the following conditions are met: # # 1. Redistributions of this script must retain the above copyright # notice, this list of conditions and the following disclaimer. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. export LC_ALL=C # root check [ "$(whoami)" != "root" ] && { echo -e "\nYou need to be root to run this script.\n"; exit 1; } PRGNAM=${PRGNAM:-wps-office} BUILD=${BUILD:-1} ARCH=$(uname -m) # WPS Office is only available for x86_64 [ "$ARCH" != "x86_64" ] && { echo -e "\n$PRGNAM is only available for x86_64 architecture.\n"; exit 1; } BOLD="\e[1m"; CYAN="\e[96m"; GREEN="\e[92m"; RED="\e[31m"; RESET="\e[0m" log() { echo -e "\n$BOLD$CYAN$*$RESET"; } info() { echo -e "$GREEN$*$RESET"; } warn() { echo -e "$RED$BOLD$*$RESET"; } TMPDIR=/tmp/portch PKG=$TMPDIR/package-$PRGNAM PKGINFO=$PKG/var/lib/pkgtools/packages OUTPUT=${OUTPUT:-/tmp} cleanup(){ rm -rf "$TMPDIR" 2>/dev/null exit } # Fetch SBO info once: latest version + download URL SBO_DATA=$(wget -qO- "https://slackbuilds.org/slackbuilds/15.0/office/wps-office/wps-office.info" | tr -d '\r') VERSION=$(echo "$SBO_DATA" | grep '^VERSION=' | head -1 | cut -d'"' -f2) SOURCE=$(echo "$SBO_DATA" | grep '^DOWNLOAD_x86_64=' | head -1 | cut -d'"' -f2) # Terminate execution if version or source URL cannot be determined if [ -z "$VERSION" ] || [ -z "$SOURCE" ]; then echo -e "\n${RED}${BOLD}Failed to determine the latest version or download URL for $PRGNAM.${RESET}" echo -e "${RED}Please check your internet connection or SBO repository status.${RESET}\n" exit 1 fi CURRENT_VER=${VERSION%.XA} # Whitelist: default, lang_list, English and the selected locale. # NOTE: "default" must be kept - it holds templates/Normal.dotm keep_locale() { local loc="$1" target="$2" case "$loc" in default|lang_list|en|en_US) return 0 ;; esac [ -n "$target" ] && [ "$loc" = "$target" ] && return 0 return 1 } setup_locale(){ local ldir="$PKG/opt/kingsoft/wps-office/office6/mui" [ -d "$ldir" ] || return 0 log "WPS Office locale setup" local locales=() loc for loc in "$ldir"/*; do [ -d "$loc" ] || continue loc=$(basename "$loc") case "$loc" in default|lang_list|en|en_US) ;; *) locales+=("$loc");; esac done local count=${#locales[@]} [ $count -eq 0 ] && { warn "no extra locales found"; return 0; } echo "Available locales ($count):" local i=1 for loc in "${locales[@]}"; do printf " %2d) %s\n" "$i" "$loc" ((i++)) done echo local choice="" while true; do echo read -p "Locale number to keep (English always kept) [1-$count, Enter=English only]: " choice [ -z "$choice" ] && break [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "$count" ] && break warn "invalid input, try again" done local target="" [ -n "$choice" ] && target="${locales[$((choice - 1))]}" log "Removing all locales except English and ${target:-none} across entire package..." # Clean every mui dir in the package (office6 + all addons) local mui_parent loc_dir while IFS= read -r mui_parent; do for loc_dir in "$mui_parent"/*; do [ -d "$loc_dir" ] || continue loc=$(basename "$loc_dir") keep_locale "$loc" "$target" || rm -rf "$loc_dir" done done < <(find "$PKG" -type d -name "mui" 2>/dev/null) find "$PKG" -type d -name "mui" -empty -delete 2>/dev/null # CEF (embedded browser) locales: keep en-US and the selected language local cef="$PKG/opt/kingsoft/wps-office/office6/addons/cef/locales" if [ -d "$cef" ]; then local dash_target="" pak bn [ -n "$target" ] && dash_target="${target/_/-}" for pak in "$cef"/*.pak; do [ -f "$pak" ] || continue bn=$(basename "$pak" .pak) case "$bn" in en-US|"$dash_target") ;; *) rm -f "$pak" ;; esac done fi [ -n "$target" ] && info "kept: en + $target" || info "only English kept" return 0 } # Install missing formula symbol fonts install_fonts(){ log "Installing formula symbol fonts" local fdir="$PKG/usr/share/fonts/wps-fonts" mkdir -p "$fdir" local fonts="symbol.ttf wingding.ttf WINGDNG2.ttf WINGDNG3.ttf WEBDINGS.TTF mtextra.ttf" local f localf for f in $fonts; do localf=$(find /usr/share/fonts /usr/local/share/fonts "$HOME/.fonts" -iname "$f" 2>/dev/null | head -1) [ -n "$localf" ] && cp -f "$localf" "$fdir/$f" 2>/dev/null done for f in $fonts; do [ -s "$fdir/$f" ] && continue wget -q --timeout=10 --tries=1 -O "$fdir/$f" "https://cdn.jsdelivr.net/gh/IamDH4/ttf-wps-fonts@master/$f" 2>/dev/null [ -s "$fdir/$f" ] && continue wget -q --timeout=10 --tries=1 -O "$fdir/$f" "https://raw.githubusercontent.com/IamDH4/ttf-wps-fonts/master/$f" 2>/dev/null [ -s "$fdir/$f" ] || warn "failed to fetch $f" done local n=$(find "$fdir" -type f -size +1k 2>/dev/null | wc -l) info "symbol fonts installed: $n/6" [ "$n" -lt 6 ] && warn "some fonts are missing - formula symbols may not display" return 0 } MYVER="" if [ -f "/usr/bin/wps" ] || [ -d "/opt/kingsoft/wps-office" ]; then INSTALLED_PKG=$(ls /var/lib/pkgtools/packages/wps-office* 2>/dev/null | head -1) [ -n "$INSTALLED_PKG" ] && MYVER=$(basename "$INSTALLED_PKG" | cut -d'-' -f3 | sed 's/\.XA$//') fi if [ -n "$MYVER" ] && [ "$MYVER" == "$CURRENT_VER" ]; then echo -e "You have the latest ${GREEN}$MYVER${RESET} version of $PRGNAM" sleep 5 exit fi read -p "$(echo -e "Would you like to build $PRGNAM ${GREEN}$VERSION${RESET} xzm module? [y/n]")" -n 1 -r -s && echo [[ ! $REPLY =~ ^[Yy]$ ]] && exit # Full clean of the build directory to avoid leftovers from interrupted runs rm -rf "$TMPDIR" mkdir -p "$TMPDIR" "$PKG" cd "$TMPDIR" log "Downloading ${PRGNAM}-${VERSION}" wget -q --show-progress -c "$SOURCE" -O "${PRGNAM}.deb" || { warn "Download failed."; cleanup; } log "Extracting ${PRGNAM}-${VERSION}" rm -f data.tar.* control.tar.* debian-binary ar x "${PRGNAM}.deb" || { warn "Not a valid deb package."; cleanup; } DATA_ARCHIVE=$(ls data.tar.* 2>/dev/null | head -1) [ -z "$DATA_ARCHIVE" ] && { warn "No data archive found."; cleanup; } tar --no-same-owner -xf "$DATA_ARCHIVE" || { warn "Failed to extract data archive."; cleanup; } mv opt usr etc "$PKG/" # Remove docs and junk rm -rf "$PKG/usr/share/doc" "$PKG/usr/share/man" "$PKG/opt/kingsoft/wps-office/office6/doc" 2>/dev/null find "$PKG" \( -name "*.bak" -o -name "*~" -o -iname "README*" -o -iname "LICENSE*" \ -o -iname "CHANGELOG*" -o -iname "CREDITS*" -o -iname "*legalnotices*" \) -delete 2>/dev/null O6="$PKG/opt/kingsoft/wps-office/office6" # Remove bundled libs conflicting with system ones rm -f "$O6"/libstdc++* "$O6"/libjpeg* "$O6"/libpng* "$O6"/libfreetype* "$O6"/libfontconfig* 2>/dev/null # Remove Chinese-only plugins, promo content and extra skins (self-contained, safe) rm -rf "$O6/addons/kweibo" \ "$O6/addons/kphoneticsymbol" \ "$O6/addons/ksoformatproof" \ "$O6/addons/kfeedback/db/personal_cn" \ "$O6/addons/kskincenter/blackgold_res" \ "$O6/addons/cef/devtools_resources.pak" \ "$O6/data/chinesesegment" \ "$O6/data/friso.ini" \ "$O6/data/Pinyin.dic" \ "$O6/skins/2018white_dark" \ "$O6/skins/2019gov" \ "$O6/skins/2020dark_pdf" \ "$O6/mui/default/resource/imglib" \ "$PKG/opt/kingsoft/wps-office/desktops" 2>/dev/null # Remove Chinese OA integration script rm -f "$O6/oa/wpsoaassist.sh" 2>/dev/null rmdir "$O6/oa" 2>/dev/null # Copy mimetypes icons to apps if [ -d "$PKG/usr/share/icons/hicolor" ]; then cd "$PKG/usr/share/icons/hicolor" for d in */mimetypes; do [ -d "$d" ] && mkdir -p "${d%mimetypes}apps" && cp -a "$d"/wps-office2019* "${d%mimetypes}apps/" 2>/dev/null done cd "$TMPDIR" fi # libcef.so symlink for the embedded browser [ -f "$O6/addons/cef/libcef.so" ] && [ ! -f "$O6/libcef.so" ] && ln -sf addons/cef/libcef.so "$O6/libcef.so" # Add StartupWMClass to desktop files for f in "$PKG/usr/share/applications"/wps-office-*.desktop; do [ -f "$f" ] && ! grep -q StartupWMClass "$f" && \ echo "StartupWMClass=$(basename "$f" .desktop | sed 's/wps-office-//')" >> "$f" done # Strip only executable ELF files in office6, in parallel find "$O6" -type f -executable -print0 2>/dev/null | xargs -0 -r -P "$(nproc)" strip --strip-unneeded 2>/dev/null install_fonts setup_locale # Download the menu icon only if not already present mkdir -p "$PKG/usr/share/pixmaps" [ -f "$PKG/usr/share/pixmaps/wps-office.png" ] || \ wget -q --timeout=10 --tries=1 -O "$PKG/usr/share/pixmaps/wps-office.png" \ 'https://slackbuilds.org/slackbuilds/15.0/office/wps-office/wps-office.png' 2>/dev/null cd "$PKG" mkdir -p "$PKGINFO" { echo "PACKAGE NAME: $PRGNAM-$VERSION-$ARCH" echo "PACKAGE DESCRIPTION:" echo "$PRGNAM: $PRGNAM (office productivity suite)" echo "$PRGNAM:" echo "$PRGNAM: WPS Office is a lightweight, fast and feature-rich" echo "$PRGNAM: alternative to Microsoft Office." echo "$PRGNAM:" echo "$PRGNAM: https://www.wps.com/" echo "$PRGNAM:" echo "FILE LIST:" find . -not -path './var' -not -path './var/*' -not -name '.' | sed 's|^\./||' } > "$PKGINFO/$PRGNAM-$VERSION-$ARCH" # NOTE: printing requires the cups module in the target system dir2xzm "$PKG" "$OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD.xzm" if [ -f "$OUTPUT/${PRGNAM}-${VERSION}-${ARCH}-${BUILD}.xzm" ]; then echo -e "\n${BOLD}Your $PRGNAM module is at: ${GREEN}${BOLD}$OUTPUT/$PRGNAM-$VERSION-${ARCH}-${BUILD}.xzm${RESET}\n${BOLD}Please copy it to your modules folder to survive a reboot.${RESET}\n" else echo -e "\n${RED}${BOLD}Failed. Your $PRGNAM module is not built.${RESET}\n" fi cleanup