#!/bin/bash
# $Id: librewolf.SlackBuild,v 1.2 2025/04/29 06:31:41 root Exp root $
# Copyright 2025  Eric Hameleers, Eindhoven, NL
# All rights reserved.
#
#   Permission to use, copy, modify, and distribute this software for
#   any purpose with or without fee is hereby granted, provided that
#   the above copyright notice and this permission notice appear in all
#   copies.
#
#   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
#   CONTRIBUTORS 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.
# -----------------------------------------------------------------------------
#
# Slackware SlackBuild script 
# ===========================
# By:          Eric Hameleers <alien@slackware.com>
# For:         librewolf
# Descr:       a custom version of Firefox, focused on privacy, security 
# URL:         https://librewolf.net/
# Build needs: (Slackware 15.0) cbindgen, llvm >= 20, rust >= 1.86
# Needs:       
# Changelog:   
# 137.0.2_1-1: 27/apr/2025 by Eric Hameleers <alien@slackware.com>
#              * Initial build.
# 
# Run 'sh librewolf.SlackBuild' to build a Slackware package.
# The package (.t?z) and .txt file as well as build logs are created in /tmp .
# Install the package using 'installpkg' or 'upgradepkg --install-new'.
#
# -----------------------------------------------------------------------------
#
# This script tries to stay close to the mozilla-firefox.SlackBuild of Slackware
#
# -----------------------------------------------------------------------------


PRGNAM=librewolf
SRCVER=${SRCVER:-154.0-2}
VERSION=$(echo $SRCVER |tr - _)
BUILD=${BUILD:-1}
NUMJOBS=${NUMJOBS:-" -j$(nproc) "}
TAG=${TAG:-_lngn}

DOCS="AUTHORS LICENSE README*"

# Where do we look for sources?
SRCDIR=$(cd $(dirname $0); pwd)

# Place to build (TMP) package (PKG) and output (OUTPUT) the program:
TMP=${TMP:-/tmp/build}
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-/tmp}

SOURCE="$SRCDIR/${PRGNAM}-${SRCVER}.tar.gz"
SRCURL="https://librewolf.dev/api/packages/$PRGNAM/generic/${PRGNAM}-source/${SRCVER}/${PRGNAM}-${SRCVER}.source.tar.gz"
#SRCURL="https://codeberg.org/api/packages/$PRGNAM/generic/${PRGNAM}-source/${SRCVER}/${PRGNAM}-${SRCVER}.source.tar.gz"

# Without LANG=C, building the Python environment may fail with:
# "UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 36: ordinal not in range(128)"
LANG=C

# Add a shell script to start the browser binary with MOZ_ALLOW_DOWNGRADE=1
# to avoid backing up (and disabling) the user profile if a browser downgrade
# is detected. We made it fine for years without this feature, and all the
# feedback we've seen suggests that it is causing more problems than it
# solves. For example, this feature causes a profile reset trying to switch
# between a 32-bit and 64-bit browser on installations that share a common
# /home directory. If you want to build with the stock default behavior, set
# this to something other than "YES":
MOZ_ALLOW_DOWNGRADE=${MOZ_ALLOW_DOWNGRADE:-YES}

# Firefox has been requiring more and more memory, especially while linking
# libxul. If it fails to build natively on x86 32-bit, it can be useful to
# attempt the build using an x86_64 kernel and a 32-bit userspace. Detect this
# situation and set the ARCH to i686. Later in the script we'll add some
# options to the .mozconfig so that the compile will do the right thing.
if [ "$(uname -m)" = "x86_64" -a "$(file -L /usr/bin/gcc | grep 386 | grep 32-bit)" != "" ]; then
  COMPILE_X86_UNDER_X86_64=true
  ARCH=i686
else
  COMPILE_X86_UNDER_X86_64=false
fi

# Choose a compiler (gcc/g++ or clang/clang++):
export CC=${CC:-clang}
export CXX=${CXX:-clang++}

# Set linker to use:
if [ "$CC" = "clang" -a "$(which lld 2> /dev/null)" = "/usr/bin/lld" ]; then
  # Upstream default:
  LINKER=lld
else
  LINKER=bfd
fi

# Keep memory usage as low as possible when linking:
if [ ! "$LINKER" = "lld" ]; then
  SLKLDFLAGS=" -Wl,--as-needed -Wl,--no-keep-memory -Wl,--stats -Wl,--reduce-memory-overheads"
  export LDFLAGS="$SLKLDFLAGS"
  export MOZ_LINK_FLAGS="$SLKLDFLAGS"
fi

# Put Rust objects on a diet to keep the linker from running into memory
# issues (especially on 32-bit):
export RUSTFLAGS="-Cdebuginfo=0"

##
## --- with a little luck, you won't have to edit below this point --- ##
##

# Automatically determine the architecture we're building on:
if [ -z "$ARCH" ]; then
  case "$(uname -m)" in
    i?86) ARCH=i586 ;;
    arm*) ARCH=arm ;;
    # Unless $ARCH is already set, use uname -m for all other archs:
    *) ARCH=$(uname -m) ;;
  esac
  export ARCH
fi
# Set CFLAGS/CXXFLAGS and LIBDIRSUFFIX:
case "$ARCH" in
  i?86)      SLKCFLAGS="-g0"
             SLKLDFLAGS=""; LIBDIRSUFFIX=""
             ;;
  x86_64)    SLKCFLAGS="-g0 -fPIC"
             SLKLDFLAGS="-L/usr/lib64"; LIBDIRSUFFIX="64"
             ;;
  aarch64)   SLKCFLAGS="-g0 -fPIC"
             SLKLDFLAGS="-L/usr/lib64"; LIBDIRSUFFIX="64"
             ;;
  arm)       SLKCFLAGS="-g0 -march=armv4 -mtune=xscale"
             SLKLDFLAGS=""; LIBDIRSUFFIX=""
             ;;
  *)         SLKCFLAGS=${SLKCFLAGS:-"-O2"}
             SLKLDFLAGS=${SLKLDFLAGS:-""}; LIBDIRSUFFIX=${LIBDIRSUFFIX:-""}
             ;;
esac

case "$ARCH" in
    arm*)    TARGET=$ARCH-slackware-linux-gnueabi ;;
    *)       TARGET=$ARCH-slackware-linux ;;
esac

# Exit the script on errors:
set -e
trap 'echo "$0 FAILED at line ${LINENO}" | tee $OUTPUT/error-${PRGNAM}.log' ERR
# Catch unitialized variables:
set -u
P1=${1:-1}

# Save old umask and set to 0022:
_UMASK_=$(umask)
umask 0022

# Create working directories:
mkdir -p $OUTPUT          # place for the package to be saved
mkdir -p $TMP/tmp-$PRGNAM # location to build the source
mkdir -p $PKG             # place for the package to be built
rm -rf $PKG/*             # always erase old package's contents
rm -rf $TMP/tmp-$PRGNAM/* # remove the remnants of previous build
rm -rf $OUTPUT/{checkout,configure,make,install,error,makepkg,patch}-$PRGNAM.log
                          # remove old log files

# Source file availability:
if ! [ -f ${SOURCE} ]; then
  echo "Source '$(basename ${SOURCE})' not available yet..."
  # Check if the $SRCDIR is writable at all - if not, download to $OUTPUT
  [ -w "$SRCDIR" ] || SOURCE="$OUTPUT/$(basename $SOURCE)"
  if [ -f ${SOURCE} ]; then echo "Ah, found it!"; continue; fi
  if ! [ "x${SRCURL}" == "x" ]; then
    echo "Will download file to $(dirname $SOURCE)"
    wget --no-check-certificate -nv -T 20 -O "${SOURCE}" "${SRCURL}" || true
    if [ $? -ne 0 -o ! -s "${SOURCE}" ]; then
      echo "Downloading '$(basename ${SOURCE})' failed... aborting the build."
      mv -f "${SOURCE}" "${SOURCE}".FAIL
      exit 1
    fi
  else
    echo "File '$(basename ${SOURCE})' not available... aborting the build."
    exit 1
  fi
fi

if [ "$P1" == "--download" ]; then
  echo "Download complete."
  exit 0
fi

# --- PACKAGE BUILDING ---

echo "++"
echo "|| $PRGNAM-$VERSION"
echo "++"

cd $TMP/tmp-$PRGNAM
echo "Extracting the source archive(s) for $PRGNAM..."
tar -xf ${SOURCE}
if [ -d source ]; then mv -i source $PRGNAM-$SRCVER ; fi
cd $PRGNAM-$SRCVER
chown -R root:root .
chmod -R u+w,go+r-w,a+rX-st .

#patch -Np1 -i $SRCDIR/librewolf.patch

echo Building ...
export LDFLAGS="$SLKLDFLAGS"
export CXXFLAGS="$SLKCFLAGS"
export CFLAGS="$SLKCFLAGS"

# Our building options, in a configure-like display ;)
# Note: NSS/NSPR is too old on Slackware 15.0, so we use the internal version.
OPTIONS="\
  --with-app-name=${PRGNAM} \
  --with-branding=browser/branding/${PRGNAM} \
  --prefix=/usr \
  --libdir=/usr/lib${LIBDIRSUFFIX} \
  --with-l10n-base=$TMP/tmp-$PRGNAM/$PRGNAM-$SRCVER/lw/l10n \
  --with-system-zlib \
  --with-unsigned-addon-scopes=app,system \
  --without-system-nss \
  --without-system-nspr \
  --without-wasm-sandboxed-libraries \
  --allow-addon-sideload \
  --enable-alsa \
  --enable-pulseaudio \
  --enable-application=browser \
  --enable-linker=$LINKER \
  --enable-release \
  --enable-optimize \
  --disable-bootstrap \
  --disable-default-browser-agent \
  --disable-strip \
  --disable-install-strip \
  --disable-tests \
  --enable-cpp-rtti \
  --enable-accessibility \
  --disable-crashreporter \
  --disable-debug-symbols \
  --disable-debug \
  --disable-elf-hack \
  --disable-updater"


#export MACH_USE_SYSTEM_PYTHON="1"
export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=pip
export CFLAGS="$SLKCFLAGS"
export CXXFLAGS="$SLKCFLAGS -fno-delete-null-pointer-checks -Wno-error=c++11-narrowing-const-reference"
export MOZ_MAKE_FLAGS="$NUMJOBS"
export MOZBUILD_STATE_PATH="$TMP/tmp-$PRGNAM/$PRGNAM-$SRCVER/.mozbuild"
export MOZ_APP_REMOTINGNAME="$PRGNAM"
export MOZ_BUILD_DATE="$(date +%Y%m%d)"
export MOZ_NOSPAM=1
export MOZ_REQUIRE_SIGNING=

# Clear some variables that could break the build
unset DBUS_SESSION_BUS_ADDRESS ORBIT_SOCKETDIR SESSION_MANAGER \
  XDG_SESSION_COOKIE XAUTHORITY MAKEFLAGS

# Assemble our .mozconfig, we use this method for building, seems
# needed for PGO.
echo ". \$topsrcdir/browser/config/mozconfig" > .mozconfig

## Mozilla devs enforce using an objdir for building
## https://developer.mozilla.org/en/Configuring_Build_Options#Building_with_an_objdir
#mkdir obj
#echo "mk_add_options MOZ_OBJDIR=$(pwd)/obj" >> .mozconfig

# Don't phone home:
cat <<EOT >> .mozconfig
mk_add_options MOZ_CRASHREPORTER=0
mk_add_options MOZ_DATA_REPORTING=0
mk_add_options MOZ_SERVICES_HEALTHREPORT=0
mk_add_options MOZ_TELEMETRY_REPORTING=0
EOT

# Tell .mozconfig about the selected compiler:
echo "export CC=\"${CC}\"" >> .mozconfig
echo "export CXX=\"${CXX}\"" >> .mozconfig

if [ "$COMPILE_X86_UNDER_X86_64" = "true" ]; then
  # Compile for i686 under an x86_64 kernel:
  echo "ac_add_options --host=i686-pc-linux-gnu" >> .mozconfig
  echo "ac_add_options --target=i686-pc-linux-gnu" >> .mozconfig
fi

# Add the $OPTIONS above to .mozconfig:
for option in $OPTIONS; do echo "ac_add_options $option" >> .mozconfig; done

# Move the original mozconfig out of the way or else mach will barf:
mv -i mozconfig{,.orig}

# Do a normal build (no PGO):
./mach build 2>&1 | tee $OUTPUT/make-${PRGNAM}.log
./mach buildsymbols 2>&1 | tee -a $OUTPUT/make-${PRGNAM}.log
DESTDIR=$PKG ./mach install 2>&1 | tee -a $OUTPUT/install-${PRGNAM}.log

# If MOZ_ALLOW_DOWNGRADE=YES, replace the /usr/bin/$PRGNAM symlink with a
# shell script that sets the MOZ_ALLOW_DOWNGRADE=1 environment variable so
# that a detected browser downgrade does not reset the user profile:
if [ "$MOZ_ALLOW_DOWNGRADE" = "YES" ]; then
  rm -f $PKG/usr/bin/$PRGNAM
  cat << EOF > $PKG/usr/bin/$PRGNAM
#!/bin/sh
#
# Shell script to start $PRGNAM.
#
# Don't reset the user profile on a detected browser downgrade:
export MOZ_ALLOW_DOWNGRADE=1

# Start $PRGNAM:
exec /usr/lib${LIBDIRSUFFIX}/$PRGNAM/$PRGNAM "\$@"
EOF
  chown root:root $PKG/usr/bin/$PRGNAM
  chmod 755 $PKG/usr/bin/$PRGNAM
fi

# Fix duplicate binary, https://bugzilla.mozilla.org/show_bug.cgi?id=658850
( cd $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM
  if cmp $PRGNAM $PRGNAM-bin ; then
    ln -sf $PRGNAM-bin $PRGNAM
  fi
)

# Use system certificates, remove potentially embedded library:
if [ -e $PKG/usr/lib${LIBDIRSUFFIX}/$PRGNAM/libnssckbi.so ]; then
  ln -sf /usr/lib${LIBDIRSUFFIX}/libnssckbi.so \
     $PKG/usr/lib${LIBDIRSUFFIX}/$PRGNAM/libnssckbi.so
fi

# Allow for plugins:
mkdir -p $PKG/usr/lib${LIBDIRSUFFIX}/$PRGNAM/plugins

# Need some default icons in the right place:
for i in 16 32 48 64 128; do
  install -D -m0644 browser/branding/${PRGNAM}/default${i}.png \
    $PKG/usr/share/icons/hicolor/${i}x${i}/apps/${PRGNAM}.png
done
install -D -m0644 ${SRCDIR}/default192x192.png \
  $PKG/usr/share/icons/hicolor/192x192/apps/${PRGNAM}.png

install -D -m0644 browser/branding/${PRGNAM}/default16.png \
  $PKG/usr/share/icons/hicolor/symbolic/apps/${PRGNAM}-symbolic.png

# Install a desktop file (thanks to Arch Linux for the content):
install -D -m0644 ${SRCDIR}/${PRGNAM}.desktop \
  $PKG/usr/share/applications/${PRGNAM}.desktop

# Add definition files:
mkdir -p $PKG/usr/lib${LIBDIRSUFFIX}/$PRGNAM/browser/defaults/preferences
cat <<EOT >$PKG/usr/lib${LIBDIRSUFFIX}/$PRGNAM/browser/defaults/preferences/vendor.js
// Use system-provided dictionaries
pref("spellchecker.dictionary_path", "/usr/share/hunspell");
EOT

mkdir -p $PKG/usr/lib${LIBDIRSUFFIX}/$PRGNAM/distribution
cat <<EOT >$PKG/usr/lib${LIBDIRSUFFIX}/$PRGNAM/distribution/distribution.ini
[Global]
id=Built by lngn.net after alien
version=1.2
about=LibreWolf

[Preferences]
app.distributor="Slackware LibreWolf Community"
app.distributor.channel=$PRGNAM
app.partner.librewolf=$PRGNAM

EOT

# Do not clobber user-modifyable content and ensure that these files are
# placed in /etc/ where they belong:
mkdir -p $PKG/etc/librewolf/distribution
mv -i $PKG/usr/lib${LIBDIRSUFFIX}/librewolf/librewolf.cfg $PKG/etc/librewolf/librewolf.cfg.new
ln -s /etc/librewolf/librewolf.cfg $PKG/usr/lib${LIBDIRSUFFIX}/librewolf/librewolf.cfg
mv -i $PKG/usr/lib${LIBDIRSUFFIX}/librewolf/distribution/policies.json $PKG/etc/librewolf/distribution/policies.json.new
ln -s /etc/librewolf/distribution/policies.json $PKG/usr/lib${LIBDIRSUFFIX}/librewolf/distribution/policies.json

# Add this to the doinst.sh:
mkdir -p $PKG/install
cat <<EOT >> $PKG/install/doinst.sh
# Handle the incoming configuration files:
config() {
  for infile in \$1; do
    NEW="\$infile"
    OLD="\$(dirname \$NEW)/\$(basename \$NEW .new)"
    # If there's no config file by that name, mv it over:
    if [ ! -r \$OLD ]; then
      mv \$NEW \$OLD
    elif [ "\$(cat \$OLD | md5sum)" = "\$(cat \$NEW | md5sum)" ]; then
      # toss the redundant copy
      rm \$NEW
    fi
    # Otherwise, we leave the .new copy for the admin to consider...
  done
}

preserve_perms() {
  NEW="\$1"
  OLD="\$(dirname \$NEW)/\$(basename \$NEW .new)"
  if [ -e \$OLD ]; then
    cp -a \$OLD \${NEW}.incoming
    cat \$NEW > \${NEW}.incoming
    mv \${NEW}.incoming \$NEW
  fi
  config \$NEW
}

config etc/librewolf/librewolf.cfg.new
config etc/librewolf/distribution/policies.json.new

# Update the desktop database:
if [ -x usr/bin/update-desktop-database ]; then
  chroot . /usr/bin/update-desktop-database usr/share/applications > /dev/null 2>&1
fi

# Update hicolor theme cache:
if [ -d usr/share/icons/hicolor ]; then
  if [ -x /usr/bin/gtk-update-icon-cache ]; then
    chroot . /usr/bin/gtk-update-icon-cache -f -t usr/share/icons/hicolor 1> /dev/null 2> /dev/null
  fi
fi

# Update the mime database:
if [ -x usr/bin/update-mime-database ]; then
  chroot . /usr/bin/update-mime-database usr/share/mime >/dev/null 2>&1
fi

EOT

# Add documentation:
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a $DOCS $PKG/usr/doc/$PRGNAM-$VERSION || true
cat $SRCDIR/$(basename $0) > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
chown -R root:root $PKG/usr/doc/$PRGNAM-$VERSION
find $PKG/usr/doc -type f -exec chmod 644 {} \;

# Compress the man page(s):
if [ -d $PKG/usr/man ]; then
  find $PKG/usr/man -type f -name "*.?" -exec gzip -9f {} \;
  for i in $(find $PKG/usr/man -type l -name "*.?") ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
fi

# Strip binaries (if any):
find $PKG | xargs file | grep -e "executable" -e "shared object" | grep ELF \
  | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true

# Add a package description:
mkdir -p $PKG/install
cat $SRCDIR/slack-desc > $PKG/install/slack-desc

# Build the package:
cd $PKG
makepkg --linkadd y --chown n $OUTPUT/${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.${PKGTYPE:-txz} 2>&1 | tee $OUTPUT/makepkg-${PRGNAM}.log
cd $OUTPUT
md5sum ${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.${PKGTYPE:-txz} > ${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.${PKGTYPE:-txz}.md5
cd -
cat $PKG/install/slack-desc | grep "^${PRGNAM}" > $OUTPUT/${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.txt

# Restore the original umask:
umask ${_UMASK_}

