Bug 32525 - unjoin debhelper
unjoin debhelper
Status: CLOSED FIXED
Product: UCS
Classification: Unclassified
Component: Join (univention-join)
UCS 3.2
Other Linux
: P5 enhancement with 1 vote (vote)
: UCS 4.0-0-errata
Assigned To: Dirk Wiesenthal
Florian Best
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2013-09-09 10:47 CEST by Philipp Hahn
Modified: 2015-02-04 15:57 CET (History)
3 users (show)

See Also:
What kind of report is it?: ---
What type of bug is this?: ---
Who will be affected by this bug?: ---
How will those affected feel about the bug?: ---
User Pain:
Enterprise Customer affected?:
School Customer affected?:
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number:
Bug group (optional):
Max CVSS v3 score:


Attachments
univention-install-joinscripts (5.78 KB, patch)
2015-01-17 14:30 CET, Dirk Wiesenthal
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Philipp Hahn univentionstaff 2013-09-09 10:47:17 CEST
The current unjoin handling is a PITA: Currently 3 scripts needs to be modified to integrate unjoin: prerm, postrm, and postinst. In there scripts are called, moved to different locations and who knows what else I'm currently missing or what needs fixing in the future because of design mistakes.
IMHO the current approach is error prone and a maintenance nightmare.

UCS should provide a script similar to dpkg-maintscript-helper, which is just called from the three locations as »ucs-join-helper "$@"« and do all the internal processing:
1. Get the name of the package from $DPKG_MAINTSCRIPT_PACKAGE
2. Find the relevant (un-)join script
3.1: Move it it prerm
3.2: Call it in postrm
3.3: Delete it in postinst

This should be further integrated with the "dh" sequencer: dh --with=ucs-unjoin would automatically create the relevant debhelper fragments, so creating the files with 30 lines of copyright and boiler-plate could be reduced to a single change in debian/rules.

Something like this (untested): (this should currently create the fragments directly, but a runtime-wrapper would allow us to further fix already shipped pckages)

### /usr/share/perl5/Debian/Debhelper/Sequence/ucs-unjoin.pm:
#!/usr/bin/perl
use warnings;
use strict;
use Debian::Debhelper::Dh_Lib;
insert_after("dh_installinit", "dh_ucs-unjoin");
1;


### /usr/bin/dh_ucs-unjoin:
#!/usr/bin/python
"""
Integrate UCS un-join scripts into package build process.
"""
# inspired by </usr/bin/dh_python2>
import os
import logging
from debpython.debhelper import DebHelper
from optparse import OptionParser, SUPPRESS_HELP

logging.basicConfig(format='%(levelname).1s: %(module)s:%(lineno)d: '
                           '%(message)s')
log = logging.getLogger(__name__)

def parse_commandline():
    parser = OptionParser()
    parser.add_option('-i', '--indep', action='store_false',
        dest='arch', default=None,
        help='act on architecture independent packages')
    parser.add_option('-a', '-s', '--arch', action='store_true',
        dest='arch', help='act on architecture dependent packages')
    parser.add_option('-q', '--quiet', action='store_false', dest='verbose',
        help='be quiet')
    parser.add_option('-p', '--package', action='append',
        help='act on the package named PACKAGE')
    parser.add_option('-N', '--no-package', action='append',
        help='do not act on the specified package')
    parser.add_option('-O', help=SUPPRESS_HELP)
    options, args = parser.parse_args(sys.argv[1:] + \
                    os.environ.get('DH_OPTIONS', '').split())
    if options.verbose or os.environ.get('DH_VERBOSE') == '1':
        log.setLevel(logging.DEBUG)
    return options

def process_packages(options):
  dh = DebHelper(options)
  for package, pdetails in dh.packages.iteritems():
    if options.arch is False and pdetails['arch'] != 'all' or \
       options.arch is True and pdetails['arch'] == 'all':
        continue
    log.debug('processing package %s...', package)
    unjoin_name = find_unjoin_file(package)
    if not unjoin_name:
      continue
    dh.autoscript(package, 'prerm', 'prerm-ucs-unjoin', unjoin_name)
    dh.autoscript(package, 'postrm', 'postrm-ucs-unjoin', unjoin_name)
    dh.autoscript(package, 'postinst', 'postinst-ucs-unjoin', unjoin_name)

def find_unjoin_file(package):
  for unjoin_name in os.listdir():
    if not unjoin_name.endswith('.uinst'):
      continue
    pkg_name = unjoin_name[2:-len('.uinst')]
    if pkg_name == package:
      return unjoin_name

def main():
   options = parse_commandlline()  
   process_packages(options)

if __name__ == '__main__':
  main()


### /usr/share/debhelper/autoscripts/prerm-ucs-unjoin:
case "$1" in
remove)
  cp /usr/lib/univention-uninstall/#ARGS# /usr/lib/univention-install/
  ;;
esac


### /usr/share/debhelper/autoscripts/postrm-ucs-unjoin:
case "$1" in
remove)
  . /usr/share/univention-lib/all.sh
  call_unjoinscript #ARGS#
  ;;
esac


### /usr/share/debhelper/autoscripts/postinst-ucs-unjoin:
case "$1" in
install|upgrade|abort-remove)
  uinst=/usr/lib/univention-install/#ARGS#
  [ -e "$uinst" ] && rm "$uinst"
  ;;
esac
Comment 1 Dirk Wiesenthal univentionstaff 2015-01-17 14:30:17 CET
Created attachment 6607 [details]
univention-install-joinscripts

Found this bug (wanted to open my own).

I wrote a script for exactly that, based on univention-install-config-registry. I also finds joinscripts (not only unjoin scripts), works with a (hopefully) upcoming Python joinscript and also takes care of installing the file with the correct permissions.

Add univention-install-joinscripts in debian/rules' override_dh_auto_install.

So no further work after putting a joinscript with the name $package.inst in the root directory.
Comment 2 Dirk Wiesenthal univentionstaff 2015-01-26 10:19:48 CET
Fixed in
  univention-join 7.1.2-6.492.201501261007

QA: I have not tested it excessively (only in one rather simple package). The idea is:
debian/rules
  override_dh_auto_install:
    univention-install-joinscript
    dh_auto_install

Add a 50$package.inst and a 50$package-uninstall.uinst in the root directory (or only the .inst file) and that should do the whole trick. If anything else is required, this bug should be REOPENED. Notably no debian/$package.install and $package.dirs need to cover the join scripts. No further actions to be taken in the control files (except for #DEBHELPER#).

The files should installed (with +x) in the correct directories. The control files preinst, postinst, etc. should do all the necessary steps (even when not created by the developer manually).

For the end user (who installs the package) no new package dependency (or version dependency) should be required.

At least this is what I hope for and what I will write down in a document while you are QA'ing.
Comment 3 Florian Best univentionstaff 2015-01-29 10:52:17 CET
The unjoin scripts aren't part of the package. Instead in debian there is a folder created named e.g.: univention-management-console-module-pkgdb-uninstall

joinscript_remove_script_from_status_file is even called if the unjoin script fails. Is this correct?

Some packages have the following lines in there POSTINST. Do we need to do this, too?
"""
if [ "$1" = "configure" ]
then
        uinst=/usr/lib/univention-install/65univention-management-console-module-pkgdb-uninstall.uinst
        [ -e "$uinst" ] && rm "$uinst"
fi
"""

Also sometimes we have cross dependencies, which require unjoinscripts of 2 packages to be called directly after each other.
"""
        # always call 65 after 50 (to remove service)
        # packages are always removed in unison because of cross-dependencies
        call_unjoinscript 50univention-pkgdb-uninstall.uinst
        call_unjoinscript 65univention-management-console-module-pkgdb-uninstall.uinst
"""
We can't use the lib then, except if it would be possible to call univention-install-joinscript with parameters for specific packages.

dh-umc-module-install adds a second call to univention-call-joinscript %s. So it is twice in the postinst if you have a UMC package.

ucslint shows now this warning:
"… join script is not mentioned in debian/rules or *.install files"

Please fix the copyright year (2007-2014 → 2015).
Comment 4 Florian Best univentionstaff 2015-01-29 10:56:56 CET
Another thing: the glob.glob() is error prone if you have two packages with names like: 'test-univention-foo' and 'univention-foo'.
Comment 5 Dirk Wiesenthal univentionstaff 2015-02-02 14:43:00 CET
(In reply to Florian Best from comment #3)
> The unjoin scripts aren't part of the package. Instead in debian there is a
> folder created named e.g.:
> univention-management-console-module-pkgdb-uninstall
> 

Fixed

> joinscript_remove_script_from_status_file is even called if the unjoin
> script fails. Is this correct?
> 
> Some packages have the following lines in there POSTINST. Do we need to do
> this, too?
> """
> if [ "$1" = "configure" ]
> then
>        
> uinst=/usr/lib/univention-install/65univention-management-console-module-
> pkgdb-uninstall.uinst
>         [ -e "$uinst" ] && rm "$uinst"
> fi
> """

I have changed the behaviour according to the suggestions above. I have implemented one initial unjoin-patch for fetchmail, where this was apparently done a bit different.

> 
> Also sometimes we have cross dependencies, which require unjoinscripts of 2
> packages to be called directly after each other.
> """
>         # always call 65 after 50 (to remove service)
>         # packages are always removed in unison because of cross-dependencies
>         call_unjoinscript 50univention-pkgdb-uninstall.uinst
>         call_unjoinscript
> 65univention-management-console-module-pkgdb-uninstall.uinst
> """
> We can't use the lib then, except if it would be possible to call
> univention-install-joinscript with parameters for specific packages.

I would rather deny using the lib here. If someone really needs it, one may change it later on, but this is a very special case. Parameters are also difficult for ucslint to handle. Maybe one should better try to avoid such situations. Maybe they only came up because the packages are older than the unjoin mechanism and there would be no dependency if one knew about (un)joinscripts in the first place.

> 
> dh-umc-module-install adds a second call to univention-call-joinscript %s.
> So it is twice in the postinst if you have a UMC package.
> 
> ucslint shows now this warning:
> "… join script is not mentioned in debian/rules or *.install files"
> 

Fixed in
  ucslint 4.0.0-5.64.201502021431

> Please fix the copyright year (2007-2014 → 2015).

Fixed

(In reply to Florian Best from comment #4)
> Another thing: the glob.glob() is error prone if you have two packages with
> names like: 'test-univention-foo' and 'univention-foo'.

Yes, fixed.
Comment 6 Florian Best univentionstaff 2015-02-03 14:38:08 CET
OK: I used nagios and pkgdb to test this.
OK: python-unjoin
OK: ucslint
YAML: OK, please add one for ucslint.
Comment 7 Florian Best univentionstaff 2015-02-03 16:47:45 CET
OK
Comment 8 Janek Walkenhorst univentionstaff 2015-02-04 15:54:58 CET
<http://errata.univention.de/ucs/4.0/68.html>
Comment 9 Janek Walkenhorst univentionstaff 2015-02-04 15:57:15 CET
<http://errata.univention.de/ucs/4.0/69.html>