# open slides
xdg-open https://presentations.nordisch.org/pw2015/#/
# adapt for your installed distribution
zypper in osc build quilt spec-cleaner
# if you want to follow the code examples
osc bco home:darix:pw2015/mosquitto
# need an account?
xdg-open https://bit.ly/opensuse_create_account
A wide variety
The most effective way to get software solutions to users
A collection of files, and more
Know your user
And even if you don't, you can make educated guesses
We very much like openSUSE
But we want software solutions to be successful everywhere
Proper packaging can accommodate most distributions fairly
How the hell can I get my package to all users?
This section displays some things done over web interface and some using CLI commands. Most of the operations are possible to do both ways
Lets create it!
home:<username>
cd somewhere-on-the-disk-where-i-want-to-store-obs-content
$ osc checkout home:<username>
$ cd home:<username>
$ mkdir mypackage
$ cp various-things mypackage/
$ osc add mypackage
$ osc commit
$ osc results
Fear not. We can do that too!
$ cd my-package-directory
$ osc build
# wait wait wait
Overall the goal of our effort should be to get the package consumed by as many people as possible.
So lets explain this on the workflow diagram https://progress.opensuse.org/workflow/factory-proposal.html.
All this translates for developer to two tasks:
$ osc sr home:<username> mypackage mydevelproject -m "My new cool package"
# wait wait wait
$ osc sr mydevelproject mypackage openSUSE:Factory
$ osc develproject openSUSE:Factory rsnapshot
Archiving
$ osc branch Archiving rsnapshot
A working copy of the branched package can be checked out with:
osc co home:scarabeus_iv:branches:Archiving/rsnapshot
$ osc co home:scarabeus_iv:branches:Archiving/rsnapshot
$ cd home:scarabeus_iv:branches:Archiving/rsnapshot
$ vi rsnapshot.spec # hackyhacky
$ osc vc
$ osc build
# wait wait wait
$ osc ci
$ osc results
$ osc sr -m "Got around to fix bnc#2345 so enjoy"
- Version bump to 4.4.4 bnc#123456
* Feature 1
* Fix 12
+ long waited bugfix for feature XYZ
- fix segfault on load incorrect document (bnc#123456)
* foo-1.2.4-buffer-owerflow.patch
- remove obsolete patch:
* foo-1.2.3-buildfix.patch
$ osc maintained rsnapshot
openSUSE:13.1:Update/rsnapshot
openSUSE:13.2:Update/rsnapshot
$ osc mbranch rsnapshot
$ osc co home:scarabeus_iv:branches:OBS_Maintained:rsnapshot
$ vi rsnapshot.openSUSE_13.1_Update/rsnapshot.spec
$ vi rsnapshot.openSUSE_13.2_Update/rsnapshot.spec
$ osc vc -m "I did fancy maintenance changes, I am great bnc#something"
$ osc ci
$ osc mr -m "Maintenance update wrt bnc#something"
$ osc sr my:devel:project package openSUSE:13.2:Update
What should the file contain?
How can I alter it without failing miserably?
Name: test
Version: 1
Release: 0
License: GPL-3.0
Summary: Testing package
Url: http://example.com
Group: some-group
Source: http://example.com/download/%{name}-%{version}.tar.xz
BuildRequires: patience-devel
Requires: patience-tools
%description
Hyperawesome test package
%prep
%setup -q
%build
%configure
make %{?_smp_mflags}
%install
make install DESTDIR=%{buildroot} %{?_smp_mflags}
%files
%defattr(-,root,root)
%doc ChangeLog README COPYING
BuildRequires: libvisio-devel >= 1.2.3
BuildRequires: cmake(GLEW) < 2.0
BuildRequires: pkgconfig(X11) >= 0.9
BuildRequires: python-imaging
Requires(post): update-alternatives
Requires: python-imaging
%requires_eq perl
Conflicts: libwriterperfect
Provides: liboldpackage = %{version}
Obsoletes: liboldpackage < %{version}
Provides: alternativepackage = %{version}
Scriptlets are shell or lua scripts executed during various phases of the package install
They have different $1 values for update/newinstall/uninstall in various phases
Requires(post): update-alternatives
%post
update-alternatives --install %{_javadir}/el_api.jar el_api \
%{_javadir}/%{name}-el-%{elspec}-api.jar 2030
Subpackages carry the syntax logic for the main spec package.
They have it's own provides/requires/scriptlets/files/etc., but buildrequires should be at main pkg for readability.
There are two types, appending name (ie. bla and bla-python) or completely renaming ones.
%package python # generates bla-python
Summary: python bindings for bla
Group: some/group
%description python
The long awaited python bindings providing a, b, and c for bla
Package libraries are bit of a special kind:
One should never ever consider packaging static library!
%package -n libbla1
Summary: library for bla
Group: System/Libraries
%description -n libbla1
Shared library to operate with bla
%post -n libbla1 -p /sbin/ldconfig
%postun -n libbla1 -p /sbin/ldconfig
%files -n libbla1
%{_libdir}/libbla.so.*
%if 0%{?something}
do stuff
%else
do other stuff
%endif
%define suse_version 1320
#
# rpm casts that into a number
0%{?suse_version} => "01320" => 1320
0%{?something_undefined} => "0" => 0
#
# => anything > 0 is true
%if 0%{?suse_version}
#
# => any suse with version bigger than 13.2
%if 0%{?suse_version} >= 1320
#
# => anything before 13.2?
%if (0%{?suse_version} && 0%{?suse_version} <= 1320)
Using systemd for all rpm based distros? No problem.
%if 0%{?suse_version} > 1230 \
|| 0%{?rhel_version} > 600 \
|| 0%{?centos_version} > 600 \
|| 0%{?fedora_version} >= 20 \
|| 0%{?el7}%{?fc20}%{?fc21}%{?fc22}
%bcond_without systemd
%else
%bcond_with systemd
%endif
Remove the "\" and the new line in the %if condition
man 5 systemd.unit
Just because you port a package to systemd, keep the sysvinit support alive for older distros.
Will show you how next ...
%if 0%{?suse_version} >= 1230
%bcond_without systemd
%else
%bcond_with systemd
%endif
[snip]
%if %{with systemd}
BuildRequires: pkgconfig(systemd)
%{?systemd_requires}
%else
PreReq: %{insserv_prereq} %{fillup_prereq}
%endif
%if %{with systemd}
install -D -m 0644 %{Source2} \
%{buildroot}%{_unitdir}/%{name}.service
install -D -m 0644 %{Source3} \
%{buildroot}%{_tmpfilesdir}/%{name}.conf
ln -sf %{_sbindir}/service %{buildroot}%{_sbindir}/rc%{name}
%else
install -D -m 0755 %{Source4} \
%{buildroot}%{_sysconfdir}/init.d/%{name}
ln -sf %{_sysconfdir}/init.d/%{name} %{buildroot}%{_sbindir}/rc%{name}
install -dD %{buildroot}%{_var}/run/%{name}/
%endif
%pre
/usr/bin/getent group %{name} || /usr/sbin/groupadd -r %{name}
/usr/bin/getent passwd %{name} || /usr/sbin/useradd -g %{name} -s /bin/false -r \
-c "Redis" -d %{_data_dir} %{name}
%if %{with systemd}
%service_add_pre %{name}.service
%endif
%post
%if %{with systemd}
%tmpfiles_create %{_tmpfilesdir}/%{name}.conf || true
%service_add_post %{name}.service
%endif
%preun
%if %{with systemd}
%service_del_preun %{name}.service
%else
%stop_on_removal %{name}
%endif
%postun
%if %{with systemd}
%service_del_postun %{name}.service
%else
%restart_on_update %{name}
%insserv_cleanup
%endif
%files
%defattr(-,root,root)
%{_sbindir}/rc%{name}
%if %{with systemd}
%{_tmpfilesdir}/%{name}.conf
%{_unitdir}/%{name}.service
%else
/etc/init.d/%{name}
%dir %attr(750,%{name},%{name}) %{_var}/run/redis/
%endif
[Unit]
Description=Redis
After=network.target
[Service]
Type=simple
User=redis
Group=redis
PIDFile=/var/run/redis/redis.pid
ExecStart=/usr/sbin/redis-server /etc/redis/redis.conf
[Install]
WantedBy=multi-user.target
#!/bin/sh
### BEGIN INIT INFO
# Provides: redis
# Required-Start: $syslog $remote_fs
# Should-Start: $time ypbind smtp
# Required-Stop: $syslog $remote_fs
# Should-Stop: ypbind smtp
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: redis key value store
# Description: redis a key value store with data types
### END INIT INFO
REDIS_BIN=/usr/sbin/redis-server
test -x $REDIS_BIN || { echo "$REDIS_BIN not installed";
if [ "$1" = "stop" ]; then exit 0;
else exit 5; fi; }
# Check for existence of needed config file and read it
# REDIS_CONFIG=/etc/sysconfig/redis
# test -r $REDIS_CONFIG || { echo "$REDIS_CONFIG not existing";
# if [ "$1" = "stop" ]; then exit 0;
# else exit 6; fi; }
# Read config
#. $REDIS_CONFIG
. /etc/rc.status
rc_reset
case "$1" in
start)
if [ ! -d /var/run/redis ] ; then
install -d -o redis -g redis -m 0750 \
/var/run/redis
fi
echo -n "Starting redis "
/sbin/startproc -u redis -g redis \
$REDIS_BIN /etc/redis/redis.conf
rc_status -v
;;
stop)
echo -n "Shutting down redis "
/sbin/killproc $REDIS_BIN
rc_status -v
;;
try-restart|condrestart)
if test "$1" = "condrestart"; then
echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
fi
$0 status
if test $? = 0; then
$0 restart
else
rc_reset # Not running is not a failure.
fi
rc_status
;;
restart)
$0 stop
$0 start
rc_status
;;
force-reload)
echo -n "Reload service redis "
/sbin/killproc -HUP $REDIS_BIN
rc_status -v
;;
reload)
echo -n "Reload service redis "
/sbin/killproc -HUP $REDIS_BIN
rc_status -v
;;
status)
echo -n "Checking for service redis "
/sbin/checkproc $REDIS_BIN
rc_status -v
;;
probe)
test /etc/redis/redis.conf \
-nt /var/run/redis.pid && echo reload
;;
*)
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
exit 1
;;
esac
rc_exit
Let's do a few advanced things
[Unit]
Description=Redis
After=network.target
PartOf=redis.target
[Service]
Type=simple
User=redis
Group=redis
PrivateTmp=true
PIDFile=/var/run/redis/%i.pid
ExecStart=/usr/sbin/redis-server /etc/redis/%i.conf
Restart=on-failure
[Install]
WantedBy=multi-user.target redis.target
Disclaimer: those recommendations might be a bit biased to "more secure"
Or does that program really needs root permissions
... this dbus service or be started by default
Open an audit bug and assign it to the security-team
Those who display courage or self-sacrifice for the greater good
-- Wikipedia
Dimstar says: "It's not all that bad."
You have a question later? Use our packaging mailinglist