Files
weewx/pkg/weewx.spec.in
2025-10-13 20:17:24 -04:00

518 lines
16 KiB
RPMSpec

# spec for building a weewx rpm for redhat or suse systems
# License: GPLv3
# Author: (c) 2013-2025 Matthew Wall
# the operating system release number is specified externaly, so that we can
# do cross-release (but not cross-platform) packaging.
%global os_target OSREL
%global relnum RPMREVISION
%global weewx_version WEEWX_VERSION
# suse 15: python3
%if 0%{?suse_version} && "%{os_target}" == "15"
%define app_group Productivity/Scientific/Other
%define relos .suse15
%define platform suse
%define deps python3, python3-importlib_resources, python3-configobj, python3-Cheetah3, python3-Pillow, python3-pyserial, python3-usb, python3-ephem
%define python python3
%endif
# rh: python3 on redhat, fedora, centos, rocky
%if "%{_vendor}" == "redhat"
%define app_group Applications/Science
%define platform redhat
# disable shebang mangling. see https://github.com/atom/atom/issues/21937
%undefine __brp_mangle_shebangs
%if "%{os_target}" == "8"
%define relos .el8
# rh8 ships with python 3.6, which has pre-built modules required by weewx.
# weewx also requires the importlib.resource module from python 3.7, which is
# backported to python 3.6. python 3.8, python 3.9, and python 3.11 are also
# available on rh8, but none of the modules required by weewx are available for
# those python (as of nov2023).
%define deps python3, python3-importlib-resources, python3-configobj, python3-cheetah, python3-pillow, python3-pyserial, python3-pyusb, python3-ephem
%define python python3
%endif
%if "%{os_target}" == "9"
%define relos .el9
# rh9 ships with python 3.9, which has pre-built modules required by weewx.
# python3-cheetah, python3-pillow are in epel
# ephem is not available for redhat9
%define deps python3, python3-configobj, python3-cheetah, python3-pillow, python3-pyserial, python3-pyusb
%define python python3
%endif
%if "%{os_target}" == "10"
%define relos .el10
# rh10 ships with python 3.12, which has pre-built modules required by weewx.
# python3-cheetah, python3-pillow are in epel
# ephem is not available for redhat10
%define deps python3, python3-configobj, python3-cheetah, python3-pillow, python3-pyserial, python3-pyusb
%define python python3
%endif
%endif
%global release %{relnum}%{?relos:%{relos}}
%global dst_code_dir %{_datadir}/weewx
%global dst_cfg_dir %{_sysconfdir}/weewx
%global dst_user_dir %{dst_cfg_dir}/bin/user
%global dst_doc_dir %{_datadir}/weewx-doc
%global cfg_file %{dst_cfg_dir}/weewx.conf
%global systemd_dir %{_unitdir}
%global udev_dir %{_udevrulesdir}
%global sqlite_root /var/lib/weewx
%global html_root /var/www/html/weewx
%define entry_points weewxd weectl
%define cfgapp %{python} /usr/share/weewx/weectl.py
Summary: weather software
Name: weewx
Version: %{weewx_version}
Release: %{release}
Group: %{app_group}
Source: %{name}-%{version}.tar.gz
URL: https://www.weewx.com
License: GPLv3
AutoReqProv: no
Requires: %{deps}
Requires(pre): /usr/bin/getent, /usr/sbin/groupadd, /usr/sbin/useradd
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n)
BuildArch: noarch
%description
weewx interacts with a weather station to produce graphs, reports, and HTML
pages. weewx can upload data to weather services such as WeatherUnderground,
PWSweather.com, or CWOP.
# define some macros for use in the scriptlets
# if there is already a database directory, then use ownership of that to
# determine what user/group we should use for permissions and running.
# otherwise, use 'weewx' for user and group.
%define weewx_get_user_info \
WEEWX_HOME="${WEEWX_HOME:-/var/lib/weewx}" \
WEEWX_USER="${WEEWX_USER:-weewx}" \
WEEWX_GROUP="${WEEWX_GROUP:-weewx}" \
if [ -d %{sqlite_root} ]; then \
TMP_USER=$(stat -c "%%U" %{sqlite_root}) \
if [ "$TMP_USER" != "root" -a "$TMP_USER" != "weewx" -a "$TMP_USER" != "UNKNOWN" ]; then \
WEEWX_USER=$TMP_USER \
WEEWX_GROUP=$(stat -c "%%G" %{sqlite_root}) \
fi \
fi
%prep
%setup -q
%build
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}%{dst_code_dir}
mkdir -p %{buildroot}%{dst_cfg_dir}
mkdir -p %{buildroot}%{dst_doc_dir}
mkdir -p %{buildroot}%{_bindir}
# rpm wants copyright and license even if no docs
cp docs_src/copyright.md %{buildroot}%{dst_doc_dir}/copyright
cp LICENSE.txt %{buildroot}%{dst_doc_dir}/license
# copy the weewx code
cp -r src/* %{buildroot}%{dst_code_dir}
# copy the ancillary files to the correct location
cp -r src/weewx_data/examples %{buildroot}%{dst_cfg_dir}
cp -r src/weewx_data/util/import %{buildroot}%{dst_cfg_dir}
cp -r src/weewx_data/util/logwatch %{buildroot}%{dst_cfg_dir}
cp -r src/weewx_data/util/rsyslog.d %{buildroot}%{dst_cfg_dir}
cp -r src/weewx_data/util/logrotate.d %{buildroot}%{dst_cfg_dir}
mkdir %{buildroot}%{dst_cfg_dir}/systemd
cp pkg/etc/systemd/system/weewx.service %{buildroot}%{dst_cfg_dir}/systemd
cp pkg/etc/systemd/system/weewx@.service %{buildroot}%{dst_cfg_dir}/systemd
mkdir %{buildroot}%{dst_cfg_dir}/udev
cp pkg/etc/udev/rules.d/weewx.rules %{buildroot}%{dst_cfg_dir}/udev
# create the weewx configuration
sed \
-e 's:HTML_ROOT = public_html:HTML_ROOT = %{html_root}:' \
-e 's:SQLITE_ROOT = .*:SQLITE_ROOT = %{sqlite_root}:' \
src/weewx_data/weewx.conf > %{buildroot}%{dst_cfg_dir}/weewx.conf
# make a copy of the generic configuration file
cp %{buildroot}%{dst_cfg_dir}/weewx.conf %{buildroot}%{dst_cfg_dir}/weewx.conf-%{weewx_version}
# create the entry points
for f in %{entry_points}; do \
sed \
-e 's:WEEWX_BINDIR=.*:WEEWX_BINDIR=/usr/share/weewx:' \
-e 's:WEEWX_PYTHON=.*:WEEWX_PYTHON=%{python}:' \
bin/$f > %{buildroot}%{_bindir}/$f; \
done
%pre
# create the weewx user and group if they do not yet exist
create_user() {
if ! /usr/bin/getent group | grep -q "^$WEEWX_GROUP"; then
echo -n "Adding system group $WEEWX_GROUP..."
/usr/sbin/groupadd -r $WEEWX_GROUP > /dev/null
echo "done"
fi
if ! /usr/bin/getent passwd | grep -q "^$WEEWX_USER"; then
echo -n "Adding system user $WEEWX_USER..."
/usr/sbin/useradd -r -g $WEEWX_GROUP -M -d $WEEWX_HOME -s /sbin/nologin $WEEWX_USER > /dev/null
echo "done"
fi
}
# add the user doing the install to the weewx group, if appropriate
add_to_group() {
if [ "$WEEWX_GROUP" != "root" ]; then
# see who is running the installation
inst_user=$(id -nu)
if [ "x$SUDO_USER" != "x" ]; then
inst_user=$SUDO_USER
fi
# put the user who is doing the installation into the weewx group,
# but only if it is not root or the weewx user.
if [ "x$inst_user" != "x" -a "$inst_user" != "root" -a "$inst_user" != "$WEEWX_USER" ]; then
# if user is already in the group, then skip it
if ! /usr/bin/getent group $WEEWX_GROUP | grep -q $inst_user; then
echo "Adding user $inst_user to group $WEEWX_GROUP"
usermod -aG $WEEWX_GROUP $inst_user
else
echo "User $inst_user is already in group $WEEWX_GROUP"
fi
fi
fi
}
%weewx_get_user_info
create_user
add_to_group
if [ $1 -gt 1 ]; then
# this is an upgrade
if [ -f %{cfg_file} ]; then
echo Saving previous config as %{cfg_file}.prev
cp -p %{cfg_file} %{cfg_file}.prev
fi
fi
%post
# create a sane configuration file with simulator as the station type
install_weewxconf() {
%{cfgapp} station reconfigure --config=%{cfg_file} --driver=weewx.drivers.simulator --no-prompt --no-backup > /dev/null
}
# this is an upgrade
# upgrade a copy of the previous config to create the upgraded version, but
# do not touch the user's configuration.
# weewx.conf - user's conf (old)
# weewx.conf-new - new conf for this weewx version
# weewx.conf-old-new - user's conf upgraded to this weewx version
# weewx.conf.rpmnew - new conf from this rpm (created by rpm rules)
merge_weewxconf() {
if [ -f %{cfg_file}.prev ]; then
OLDVER=$(get_conf_version %{cfg_file}.prev)
if [ -f %{cfg_file}-%{weewx_version} ]; then
MNT=${OLDVER}-%{weewx_version}
echo Creating maintainer config file as %{cfg_file}-$MNT
cp -p %{cfg_file}.prev %{cfg_file}-$MNT
%{cfgapp} station upgrade --config=%{cfg_file}-$MNT --dist-config=%{cfg_file}-%{weewx_version} --what=config --no-backup --yes > /dev/null
fi
fi
}
precompile() {
rc=$(%{python} -m compileall -q -x 'user' %{dst_code_dir})
if [ "$rc" != "" ]; then
echo "Pre-compile failed!"
echo "$rc"
fi
}
# get the version number from the specified file, without the rpm revisions
get_conf_version() {
v=$(grep '^version.*=' $1 | sed -e 's/\s*version\s*=\s*//' | sed -e 's/-.*//')
if [ "$v" = "" ]; then
# someone might have messed with the version string
v="xxx"
fi
echo $v
}
set_permissions() {
usr=$1
grp=$2
dir=$3
find $3 -type f -exec chmod 664 {} \;
find $3 -type d -exec chmod 2775 {} \;
chown -R $usr $dir
chgrp -R $grp $dir
}
# if there is a defaults file and it contains values that would interfere with
# this installation, make a copy then insert values that we know will work.
setup_defaults() {
dflts=/etc/default/weewx
if [ -f $dflts ]; then
WEEWX_PYTHON=$(grep "^WEEWX_PYTHON\s*=" $dflts | sed -e "s/WEEWX_PYTHON\s*=\s*//")
if [ ! -z "$WEEWX_PYTHON" -a "$WEEWX_PYTHON" != "python3" ]; then
REPLACE_PYTHON=1
fi
WEEWX_BINDIR=$(grep "^WEEWX_BINDIR\s*=" $dflts | sed -e "s/WEEWX_BINDIR\s*=\s*//")
if [ ! -z "$WEEWX_BINDIR" -a "$WEEWX_BINDIR" != "/usr/share/weewx" ]; then
REPLACE_BINDIR=1
fi
if [ "$REPLACE_PYTHON" != "" -o "$REPLACE_BINDIR" != "" ]; then
echo "Saving old defaults to ${dflts}-$ts"
cp -p $dflts ${dflts}-$ts
if [ "$REPLACE_PYTHON" != "" ]; then
sed -i -e "s:^WEEWX_PYTHON\s*=.*:WEEWX_PYTHON=python3:" $dflts
fi
if [ "$REPLACE_BINDIR" != "" ]; then
sed -i -e "s:^WEEWX_BINDIR\s*=.*:WEEWX_BINDIR=/usr/share/weewx:" $dflts
fi
fi
fi
}
# install the init files
setup_init() {
if [ -d %{systemd_dir} ]; then
for f in weewx.service weewx@.service; do
sed \
-e "s/User=.*/User=${WEEWX_USER}/" \
-e "s/Group=.*/Group=${WEEWX_GROUP}/" \
%{dst_cfg_dir}/systemd/$f > %{systemd_dir}/$f
done
if [ "$pid1" = "systemd" ]; then
systemctl daemon-reload > /dev/null 2>&1 || :
fi
fi
}
# remove any previous init configuration that could interfere
migrate_init() {
if [ -f /etc/init.d/weewx ]; then
chkconfig --del weewx > /dev/null 2>&1
mv /etc/init.d/weewx /etc/init.d/weewx.rpmsave
fi
if [ -f /etc/init.d/weewx-multi ]; then
chkconfig --del weewx-multi > /dev/null 2>&1
mv /etc/init.d/weewx-multi /etc/init.d/weewx-multi.rpmsave
fi
}
# install the udev rules
setup_udev() {
if [ -d %{udev_dir} ]; then
sed \
-e "s/GROUP=\"weewx\"/GROUP=\"${WEEWX_GROUP}\"/" \
%{dst_cfg_dir}/udev/weewx.rules > %{udev_dir}/60-weewx.rules
fi
}
# copy the skins if there are not already skins in place
setup_skins() {
if [ ! -d %{dst_cfg_dir}/skins ]; then
cp -rp %{dst_code_dir}/weewx_data/skins %{dst_cfg_dir}
fi
}
# create the user extensions directory if one does not already exist
setup_user_dir() {
if [ ! -d %{dst_user_dir} ]; then
mkdir -p %{dst_user_dir}
cp %{dst_code_dir}/weewx_data/bin/user/__init__.py %{dst_user_dir}
cp %{dst_code_dir}/weewx_data/bin/user/extensions.py %{dst_user_dir}
fi
}
# create the database directory. set ownership on everything in the directory
# but do not mess with permissions.
setup_database_dir() {
echo "Configuring database directory %{sqlite_root}"
mkdir -p %{sqlite_root}
chmod 2775 %{sqlite_root}
find %{sqlite_root} -name "*.sdb" -exec chmod 664 {} \;
chown -R $WEEWX_USER:$WEEWX_GROUP %{sqlite_root}
}
# create the reports directory
setup_reporting_dir() {
echo "Configuring reporting directory %{html_root}"
mkdir -p %{html_root}
set_permissions $WEEWX_USER $WEEWX_GROUP %{html_root}
}
# set the permissions on the configuration, skins, and extensions
set_config_permissions() {
echo "Setting permissions $WEEWX_USER:$WEEWX_GROUP on %{dst_cfg_dir}"
set_permissions $WEEWX_USER $WEEWX_GROUP %{dst_cfg_dir}
# ensure that the configuration files are not world-readable so that
# we protect any passwords and tokens
chmod 660 /etc/weewx/*.conf*
}
# if this is an upgrade from V4, copy any extensions to the V5 location
migrate_extensions() {
if [ -d /usr/share/weewx/user ]; then
echo "Copying old extensions to /etc/weewx/bin/user"
cp -rp /usr/share/weewx/user/* /etc/weewx/bin/user
echo "Moving old extensions to /usr/share/weewx/user-$ts"
mv /usr/share/weewx/user /usr/share/weewx/user-$ts
fi
}
# we explicitly do *not* pay attention to the systemd.preset, since that
# just causes unnecessary confusion, for example between presets for a
# server or workstation configuration, or even from one version of systemd
# to another. just always enable weewx.
enable_weewxd() {
if [ "$1" = "systemd" ]; then
cfgs=$2
if [ "$cfgs" = "" -o "$cfgs" = "weewx" ]; then
systemctl enable weewx > /dev/null 2>&1 || :
else
for i in $cfgs; do
systemctl enable weewx@$i > /dev/null 2>&1 || :
done
fi
fi
}
start_weewxd() {
if [ "$1" = "systemd" ]; then
cfgs=$2
if [ "$cfgs" = "" ]; then
systemctl start weewx > /dev/null 2>&1 || :
else
for i in $cfgs; do
systemctl start weewx@$i > /dev/null 2>&1 || :
done
fi
fi
}
# just in case there is an old weewxd running somehow, shut it down
stop_old_weewxd() {
if [ "$1" = "systemd" ]; then
if [ -f /etc/init.d/weewx-multi ]; then
service stop weewx-multi > /dev/null 2>&1 || :
fi
systemctl stop weewx > /dev/null 2>&1 || :
fi
}
# see how many instances of weewxd are running
count_instances() {
NUM_INSTANCES=$(ps ax | grep weewxd | egrep -v grep | wc -l)
echo $NUM_INSTANCES
}
# timestamp for files we must move aside
ts=`/usr/bin/date +"%%Y%%m%%d%%H%%M%%S"`
# see which init system (if any) is running
pid1=none
if [ -d /run/systemd/system ]; then
pid1=systemd
fi
%weewx_get_user_info
echo "Using $WEEWX_USER:$WEEWX_GROUP as user:group"
# default to running an instance of weewxd
num_weewxd=1
if [ $1 -gt 1 ]; then
# this is an upgrade, so see if weewx is already running
num_weewxd=$(count_instances)
echo "Found $num_weewxd running instances of weewxd"
# this is an upgrade, so ensure that weewx is not running
stop_old_weewxd $pid1
fi
setup_defaults $pid1
setup_udev
if [ "$1" = "1" ]; then
# this is a new install so create a config file
install_weewxconf
elif [ $1 -gt 1 ]; then
# this is an upgrade so create a maintainers version by merging the config
merge_weewxconf
# migrate any extensions from V4 location to V5
migrate_extensions
# remove any previous init configuration that might interfere
migrate_init $pid1
fi
setup_skins
setup_user_dir
setup_database_dir
setup_reporting_dir
precompile
set_config_permissions
setup_init $pid1
enable_weewxd $pid1
if [ "$num_weewxd" != "0" ]; then
# if this is a new install, start weewx no matter what. if this
# is an upgrade, start weewx only if it was running before.
start_weewxd $pid1
fi
%preun
# 0 remove last version
# 1 first install
# 2 upgrade
# see which init system (if any) is running
pid1=none
if [ -d /run/systemd/system ]; then
pid1=systemd
fi
if [ "$1" = "0" ]; then
# this is an uninstall, so stop and remove everything
if [ "$pid1" = "systemd" ]; then
systemctl stop weewx > /dev/null 2>&1 || :
systemctl disable weewx > /dev/null 2>&1 || :
for f in weewx.service weewx@.service; do
if [ -f %{systemd_dir}/$f ]; then
rm -f %{systemd_dir}/$f
fi
done
fi
# remove udev rules
if [ -f %{udev_dir}/60-weewx.rules ]; then
rm -f %{udev_dir}/60-weewx.rules
fi
# remove any bytecompiled code
find /usr/share/weewx -name '*.pyc' -delete
find /usr/share/weewx -name __pycache__ -delete
find /etc/weewx/bin -name '*.pyc' -delete
find /etc/weewx/bin -name __pycache__ -delete
fi
# otherwise this is a first install or upgrade, so do nothing
%clean
rm -rf %{buildroot}
%files
%defattr(-,root,root)
%attr(0755,root,root) %{_bindir}/weewxd
%attr(0755,root,root) %{_bindir}/weectl
%{dst_code_dir}/
%doc %{dst_doc_dir}/
%config(noreplace) %{dst_cfg_dir}/
%changelog