#!/usr/bin/perl

=head1 NAME

dh_gnustep - perform various actions for GNUstep packages

=cut

use strict;
use warnings;
use File::Copy;
use File::Find;
use File::Path qw(remove_tree);
use Debian::Debhelper::Dh_Lib;

=head1 SYNOPSIS

B<dh_gnustep> [S<I<debhelper options>>] [B<--app>] [B<--appsupport>] [B<--bundle>] [B<--bundle-dir=>I<directory>] [B<--bug-script>] [B<--game>] [B<--move-to=>I<package>] [B<--no-cleanup>] [B<--no-move>]

=head1 DESCRIPTION

B<dh_gnustep> is a program based on L<debhelper(7)> that is
responsible for doing GNUstep-specific modifications, such as moving
files in the GNUstep hierarchy to Filesystem Hierarchy Standard
(FHS)-compliant locations.  It also adds bug-script symlinks for
GNUstep applications, removes some build system artifacts and adds
additional dependendcies to packages that need it.

For brevity and because the GNUstep directories discussed are fairly
long and cause readability issues when this manpage is being displayed
on a typical terminal, the standard GNUstep variables are used as
placeholders as follows:

B<GNUSTEP_SYSTEM_LIBRARY>
  I</usr/lib/${DEB_HOST_MULTIARCH}/GNUstep>

B<GNUSTEP_SYSTEM_HEADERS>
  I</usr/include/${DEB_HOST_MULTIARCH}/GNUstep>

B<GNUSTEP_SYSTEM_APPS>
  I</usr/lib/${DEB_HOST_MULTIARCH}/GNUstep/Applications>

B<GNUSTEP_SYSTEM_APPLICATION_SUPPORT>
  I</usr/lib/${DEB_HOST_MULTIARCH}/GNUstep/ApplicationSupport>

B<GNUSTEP_SYSTEM_BUNDLES>
  I</usr/lib/${DEB_HOST_MULTIARCH}/GNUstep/Bundles>

B<dh_gnustep> must be run after L<dh_bugfiles(1)> but before
L<dh_link(1)>.  Normally you would use an C<override_dh_link> target
but you should remember to invoke L<dh_link(1)> as the last command in
the recipe.  This is mandatory so that the created links are made
policy-compliant.  Using the C<execute_before_dh_link> target avoids
this extra step.  This program makes the following changes (all move
operations can be cancelled with the B<--no-move> option):

=over 4

=item arch-indep directories:

Moves architecture-independent directories in
B<GNUSTEP_SYSTEM_LIBRARY> to F</usr/share>.

=item library resources:

Moves library resources (B<GNUSTEP_SYSTEM_LIBRARY/Libraries>) to
F</usr/share/GNUstep/Libraries>.

=item frameworks:

Moves framework headers to B<GNUSTEP_SYSTEM_HEADERS/Frameworks> and
framework resources to F</usr/share/GNUstep/Frameworks>.

=item applications:

Moves application resource bundles to F</usr/share/GNUstep>.  This is
not done by default and requires specifying the B<--app> option.

=item application support:

Moves application support (B<GNUSTEP_SYSTEM_APPLICATION_SUPPORT>)
bundles' resources to F</usr/share/GNUstep>.  This is not done by
default and requires specifying the B<--appsupport> option.

=item bundles:

Moves bundles' (by default at B<GNUSTEP_SYSTEM_BUNDLES>) resources to
F</usr/share/GNUstep>.  This is not done by default and requires
specifying the B<--bundle> option.  The B<--bundle-dir> option can be
used for alternative non-standard directories.

=item bug-script symlinks:

By default, B<dh_gnustep> will install a bug-script symlink for any
package with a name ending with C<.app>, pointing to
F</usr/share/bug/gnustep-back-common>, so that the system and user
GNUstep backends are reported as package-specific information to the
BTS when submitting bugs.  It will also add the appropriate dependency
(via the I<${misc:Depends}> substitution variable).

Note that B<dh_gnustep> will not handle any other bug files and it
expects L<dh_bugfiles(1)> to have completed its job in order to handle
the case when the bug-script symlink must be installed as
F</usr/share/bug/package/script> (when there are F<bug-control> or
F<bug-presubj> files).  If an existing bug script is detected,
B<dh_gnustep> will emit a warning as a package can have only one
bug-script file.  In such situations the only solution is to integrate
the contents of F</usr/share/bug/gnustep-back-common> into the
existing script.

=item build system artifacts:

By default, B<dh_gnustep> will delete F<stamp.make> files which are
created and (unfortunately) installed by I<gnustep-make> for many
project types.  Likewise, it will delete F<dependencies> files created
and installed for GNUstep documentation projects.  The number and type
of the deleted files are recorded in the build log if B<DH_QUIET> is
not set.

=item additional dependencies:

For packages providing files in either B<GNUSTEP_SYSTEM_LIBRARY> or
B<GNUSTEP_SYSTEM_HEADERS>, B<dh_gnustep> will automatically add the
necessary dependency for the multiarch layout (via the
I<${misc:Depends}> substitution variable).

=back

=head1 OPTIONS

B<dh_gnustep> accepts the common L<debhelper(7)> options, and some
specific ones.  If you use any of the options below, make sure to
build-depend on gnustep-make (>= 2.9.2-2) if that version is not
already satisfied in the current stable/oldstable release.  Some
options are implemented in subsequent releases, as documented below.

=over 4

=item B<--app>

Move C<Resources>, i.e. the resource bundle of a GNUstep application
(B<GNUSTEP_SYSTEM_APPS/Foo.app/Resources>) to the
architecture-independent F</usr/share/GNUstep/Foo.app> and make the
necessary symlink.  The automatically generated F<.desktop> file is
deleted.  If the binary package contains more than one app, they are
processed independently.

Care shhould be taken when using this option because some apps contain
architecture-dependent files in their resource bundle.  Another
important point to pay attention to: if this is an existing package
which does not have its resources moved to F</usr/share>, a
F<maintscript> is required because dpkg will not switch a directory to
a symlink (and vice-versa).  B<dh_gnustep> does not handle this, see
L<dpkg-maintscript-helper(1)>.

This option is incompatible with B<--no-move> and for multi-binary
packages sometimes should be used with the appropriate B<-p> option.

=item B<--appsupport>

Move the C<Resources> directories of all bundles found in
B<GNUSTEP_SYSTEM_APPLICATION_SUPPORT> to F</usr/share>, as
subdirectories to the parent directory.  If the package ships several
bundles under B<GNUSTEP_SYSTEM_APPLICATION_SUPPORT/Palettes>, they are
moved as subdirectories to F</usr/share/GNUstep/Palettes>.

Note that bundles' resources sometimes contain architecture-dependent
files in which case the best approach is to move the
architecture-independent files manually.

This option was introduced in gnustep-make/2.9.2-3 and like B<--app>
it is incompatible with B<--no-move>.

=item B<--bundle>

=item B<--bundle-dir=>I<directory>

Move the C<Resources> directory of all bundles found in
B<GNUSTEP_SYSTEM_BUNDLES> (or an alternative directory under
B<GNUSTEP_SYSTEM_LIBRARY> if the B<--bundle-dir> option is specified)
to F</usr/share>.  If the package installs bundles in a subdirectory,
the same subdirectory will be created under F</usr/share/GNUstep>.

This option was introduced in gnustep-make/2.9.2-4 and it is
incompatible with B<--no-move>.  Furthermore, B<--bundle> and
B<--bundle-dir> are mutually exclusive.  If the package installs
bundles in the standard Bundles directory and in another non-standard
directory, you'll have to run B<dh_gnustep> twice with different
arguments if you need to move all of the resource bundles.

=item B<--bug-script>

Install bug-script symlink for the package even if its name does not
end with C<.app>.  Typically this should be done for apps which are
installed for some reason with tools or other stuff in a package with
a different name (such as I<gnustep-examples> or I<gnustep-dl2>).  It
can also be done for GUI bundles, themes, palettes, etc.  You probably
want to use the B<-p> option as well, otherwise B<dh_gnustep> will add
bug script symlinks for all binary packages.

=item B<--game>

This option must be used together with B<--app>.  It does everything
that B<--app> does as described above, and additionally moves the
symlink to the executable from F</usr/bin> to F</usr/games>.  If
F</usr/bin> is found empty afterwards, the directory is deleted.

=item B<--move-to=>I<package>

This option must be used together with B<--app>, B<--appsupport> or
B<--bundle>/B<--bundle-dir> (or any kind of combination of these
options).  If B<--app> is specified, move the resource bundle of an
application to another architecture-independent I<package>.  If
B<--appsupport> is given, move the C<Resources> directories of all
bundles found in B<GNUSTEP_SYSTEM_APPLICATION_SUPPORT> to
F</usr/share/GNUstep> in the specified I<package>.  If B<--bundle> is
specified, move the C<Resources> directories of all bundles in
B<GNUSTEP_SYSTEM_BUNDLES> (or an alternative directory if
B<--bundle-dir> is used) to F</usr/share/GNUstep> in the specified
I<package>.

If B<--app>, B<--appsupport> and B<--bundle> are used together, all
resource bundles are moved to the package specified by the option's
argument, there is no way to split them in different packages.  The
current implementation will handle more than one app per binary
package but it will fail with a multi-binary source package containing
more than one C<.app> binary package.  Likewise, if the package
contains more than one ApplicationSupport directory, they will be
processed independently as expected but the build is likely to fail if
they are in different binary packages.

Use with caution; see the EXAMPLES section for working examples.

=item B<--no-cleanup>

Do not delete F<stamp.make> and F<dependencies> files.

=item B<--no-move>

Do not perform any move operations.  Setting the DEB_GNUSTEP_NO_MOVE
environment variable to a non-empty, non-zero value has the same
effect.

=back

=head1 EXAMPLES

  execute_before_dh_link:
          dh_gnustep -pgnustep-dl2 --no-move --bug-script
          dh_gnustep --remaining-packages

Do not move any files for the I<gnustep-dl2> package (as that's
already handled manually) but install a bug-script symlink because
the package contains an application and a Gorm palette.

  execute_before_dh_link:
  ifeq (,$(filter lynkeos.app-common,$(shell dh_listpackages)))
          rm -rf debian/tmp$(GNUSTEP_SYSTEM_APPS)/Lynkeos.app/Resources
          dh_gnustep
  else
          dh_gnustep --app --move-to=lynkeos.app-common
  endif

Move the I<lynkeos.app> resource bundle to the
architecture-independent package I<lynkeos.app-common>.  When doing a
full build (arch:all + arch:any), the make conditional is false so the
move is done when operating on I<lynkeos.app>.  During an arch:any
build, no move is being done but the I<lynkeos.app> package is
processed with the the default B<dh_gnustep> behaviour, gaining a
bug-script symlink and cleaning up build artifacts.  The deletion of
the Resources directory is to eliminate a L<dh_missing(1)> error.
During an arch:all build the move is done while processing the
I<lynkeos.app-common> package.

  override_dh_link:
          dh_gnustep --app --game
          dh_link

Move the app's resource bundle to F</usr/share> and the symlink to the
executable from F</usr/bin> to F</user/games>.  Additionally, assuming
the binary package name ends with C<.app>, create a bug-script symlink
pointing to F</usr/share/bug/gnustep-back-common>.  Finally, delete
the F<stamp.make> file from the app bundle.

  execute_before_dh_link:
  ifneq (,$(filter gnustep-gui-runtime,$(shell dh_listpackages)))
          dh_gnustep -pgnustep-gui-runtime --app \
            --bundle-dir=ColorPickers --move-to=gnustep-gui-common
          dh_gnustep --remaining-packages
  else
          dh_gnustep --app --bundle-dir=ColorPickers \
            --move-to=gnustep-gui-common
  endif

Move the resource bundles of two apps and the resources of all
ColorPickers' bundles to F</usr/share> in the I<gnustep-gui-common>
package.  Note that B<dh_gnustep> will automatically figure out that
the package they are being moved from is I<gnustep-gui-runtime> and
there is no need to use debhelper's B<-p> option.  The conditional is
only necessary to support full builds so that the symlinks are created
in the I<gnustep-gui-runtime> package.

=head1 BUGS

Should implement B<-X> option.

Should do something with Java classes -- make a jar file and move from
Library/Libraries/Java to /usr/share/java -- to comply with Java policy.

=head1 CONFORMS TO

Debian Policy, version 4.7.0

FHS, version 3.0

Multiarch specification, L<https://wiki.ubuntu.com/MultiarchSpec>

=cut

init (options =>
      {
       "app" => \$dh{APP},
       "appsupport" => \$dh{APPSUPPORT},
       "bug-script" => \$dh{BUG_SCRIPT},
       "bundle" => \$dh{BUNDLE},
       "bundle-dir:s" => \$dh{BUNDLE_DIR},
       "game" => \$dh{GAME},
       "move-to:s" => \$dh{MOVE_TO},
       "no-cleanup" => \$dh{NO_CLEANUP},
       "no-move" => \$dh{NO_MOVE},
      });

my $move_to_processed = 0;
my $multiarch = dpkg_architecture_value ("DEB_HOST_MULTIARCH");
my $LIB_ROOT = "usr/lib/$multiarch/GNUstep";
my $SHARE_ROOT = "usr/share/GNUstep";
my $INCLUDE_ROOT = "usr/include/$multiarch/GNUstep";

my @ARCH_INDEP_DIRS = qw(Colors DocTemplates Fonts KeyBindings PostScript Libraries);

foreach my $package (@{$dh{DOPACKAGES}})
  {
    my $tmp = tmpdir ($package);

    # Some sanity checks.
    if ($dh{MOVE_TO}
        && !($dh{APP} || $dh{APPSUPPORT} || ($dh{BUNDLE} || $dh{BUNDLE_DIR})))
      {
        error ("Option --move-to requires --app, --appsupport or --bundle/--bundle-dir.");
      }
    if ($dh{GAME} && !$dh{APP})
      {
        error ("Option --game requires --app.");
      }
    if ($dh{BUNDLE} && $dh{BUNDLE_DIR})
      {
        error ("Options --bundle and --bundle-dir are mutually exclusive.");
      }

    # Moving stuff around for FHS compliance.
    if ($dh{NO_MOVE} || $ENV{DEB_GNUSTEP_NO_MOVE})
      {
        verbose_print ("Not moving files because --no-move was given.");

        if ($dh{APP} || $dh{APPSUPPORT} || ($dh{BUNDLE} || $dh{BUNDLE_DIR}))
          {
            error ("--app, --appsupport and --bundle/--bundle-dir cannot be used with --no-move.");
          }
        if ($dh{MOVE_TO})
          {
            error ("--move-to cannot be used with --no-move.");
          }
      }
    else
      {
        # Move arch-indep directories to usr/share/GNUstep.
        foreach my $directory (@ARCH_INDEP_DIRS)
          {
            if (-d "$tmp/$LIB_ROOT/$directory")
              {
                install_dir ("$tmp/$SHARE_ROOT/$directory");
                move ("$tmp/$LIB_ROOT/$directory",
                      "$tmp/$SHARE_ROOT/$directory")
                  or die "$package: move failed: $!";
                verbose_print ("mv $tmp/$LIB_ROOT/$directory $tmp/$SHARE_ROOT/$directory");
              }
          }

        if (-d "$tmp/$LIB_ROOT/DTDs")
          {
            install_dir ("$tmp/usr/share/xml/gnustep");
            move ("$tmp/$LIB_ROOT/DTDs", "$tmp/usr/share/xml/gnustep")
              or die "$package: move failed: $!";
            verbose_print ("mv $tmp/$LIB_ROOT/DTDs $tmp/usr/share/xml/gnustep");
          }

        if (-d "$tmp/$LIB_ROOT/Images")
          {
            install_dir ("$tmp/usr/share/pixmaps/GNUstep");
            move ("$tmp/$LIB_ROOT/Images", "$tmp/usr/share/pixmaps/GNUstep")
              or die "$package: move failed: $!";
            verbose_print ("mv $tmp/$LIB_ROOT/Images $tmp/usr/share/pixmaps/GNUstep");
          }

        if (-d "$tmp/$LIB_ROOT/Sounds")
          {
            install_dir ("$tmp/usr/share/sounds/GNUstep");
            move ("$tmp/$LIB_ROOT/Sounds", "$tmp/usr/share/sounds/GNUstep")
              or die "$package: move failed: $!";
            verbose_print ("mv $tmp/$LIB_ROOT/Sounds $tmp/usr/share/sounds/GNUstep");
          }

        # $LIB_ROOT may end up empty after these operations so attempt
        # to delete it (otherwise lintian will emit
        # package-contains-empty-directory).
        if (rmdir ("$tmp/$LIB_ROOT"))
          {
            verbose_print ("rmdir $tmp/$LIB_ROOT");
            # So may be the case with /usr/lib/${DEB_HOST_MULTIARCH}.
            if (rmdir ("$tmp/usr/lib/$multiarch"))
              {
                verbose_print ("rmdir $tmp/usr/lib/$multiarch");
                # And finally, that may be the case for /usr/lib.
                if (rmdir ("$tmp/usr/lib"))
                  {
                    verbose_print ("rmdir $tmp/usr/lib");
                  }
              }
          }

        # Find frameworks and move resources and headers.
        if (-d "$tmp/$LIB_ROOT/Frameworks")
          {
            opendir FRAMEWORKDIR, "$tmp/$LIB_ROOT/Frameworks";
            my @frameworks = grep !/^\./, readdir FRAMEWORKDIR;
            closedir FRAMEWORKDIR;
            foreach my $framework (@frameworks)
              {
                my $fwdir = "$tmp/$LIB_ROOT/Frameworks/$framework";
                opendir CURFWDIR, "$fwdir/Versions";
                my @versions = grep !/^(\.|Current$)/, readdir CURFWDIR;
                closedir CURFWDIR;
                foreach my $version (@versions)
                  {
                    if (-d "$fwdir/Versions/$version/Headers")
                      {
                        install_dir ("$tmp/$INCLUDE_ROOT/Frameworks/$framework/Versions/$version");
                        move ("$tmp/$LIB_ROOT/Frameworks/$framework/Versions/$version/Headers",
                              "$tmp/$INCLUDE_ROOT/Frameworks/$framework/Versions/$version")
                          or die "$package: move failed: $!";
                        verbose_print ("mv $tmp/$LIB_ROOT/Frameworks/$framework/Versions/$version/Headers $tmp/$INCLUDE_ROOT/Frameworks/$framework/Versions/$version");
                        make_symlink ("$LIB_ROOT/Frameworks/$framework/Versions/$version/Headers",
                                      "$INCLUDE_ROOT/Frameworks/$framework/Versions/$version",
                                      $tmp);
                      }
                    if (-d "$fwdir/Versions/$version/Resources")
                      {
                        install_dir ("$tmp/$SHARE_ROOT/Frameworks/$framework/Versions/$version");
                        move ("$tmp/$LIB_ROOT/Frameworks/$framework/Versions/$version/Resources",
                              "$tmp/$SHARE_ROOT/Frameworks/$framework/Versions/$version")
                          or die "$package: move failed: $!";
                        verbose_print ("mv $tmp/$LIB_ROOT/Frameworks/$framework/Versions/$version/Resources $tmp/$SHARE_ROOT/Frameworks/$framework/Versions/$version");
                        make_symlink ("$LIB_ROOT/Frameworks/$framework/Versions/$version/Resources",
                                      "$SHARE_ROOT/Frameworks/$framework/Versions/$version",
                                      $tmp);
                      }
                  }
                if (-l "$fwdir/Headers")
                  {
                    my $linkend = readlink "$fwdir/Versions/Current";
                    if ($linkend)
                      {
                        symlink ("Versions/$linkend",
                                 "$tmp/$INCLUDE_ROOT/Frameworks/$framework/Headers");
                        verbose_print ("ln -s $tmp/$INCLUDE_ROOT/Frameworks/$framework/Headers Versions/$linkend");
                      }
                  }
                if (-l "$fwdir/Resources")
                  {
                    my $linkend = readlink "$fwdir/Versions/Current";
                    if ($linkend)
                      {
                        symlink ("Versions/$linkend",
                                 "$tmp/$SHARE_ROOT/Frameworks/$framework/Resources");
                        verbose_print ("ln -s $tmp/$SHARE_ROOT/Frameworks/$framework/Resources Versions/$linkend");
                      }
                  }
              }
          }

        # Move apps'/bundles' resource bundles, and ApplicationSupport
        # arch-independent stuff to /usr/share/GNUstep.
        if ($dh{APP} || $dh{APPSUPPORT} || $dh{BUNDLE} || $dh{BUNDLE_DIR})
          {
            my $appdir = "$tmp/$LIB_ROOT/Applications";
            my $appsupportdir = "$tmp/$LIB_ROOT/ApplicationSupport";
            my $bundledir = "$tmp/$LIB_ROOT/Bundles";
            my $pkgdir = $tmp;

            if ($dh{BUNDLE_DIR})
              {
                $bundledir = "$tmp/$LIB_ROOT/$dh{BUNDLE_DIR}";
              }

            if ($dh{MOVE_TO})
              {
                if (!grep {$_ eq $dh{MOVE_TO}} getpackages ("indep"))
                  {
                    error ("$dh{MOVE_TO} does not exist or is arch:any.");
                  }

                # If --move-to is given, $appdir, $appsupportdir or
                # $bundledir are likely to contain only the
                # executables so we resort to debian/tmp.  This will
                # fail miserably if it's a multi-binary package with
                # several apps in different binary packages but that
                # limitation should be properly documented.
                $appdir =~ s/\Q$package\E/tmp/g;
                $appsupportdir =~ s/\Q$package\E/tmp/g;
                $bundledir =~ s/\Q$package\E/tmp/g;
                $pkgdir = tmpdir ($dh{MOVE_TO});
              }

            if ($move_to_processed)
              {
                verbose_print ("$package: --move-to is processed; skipping.");
              }
            elsif (-d $appdir && $dh{APP})
              {
                # Package may contain more than one app.
                opendir APPDIR, $appdir;
                my @apps = grep !/^\./, readdir APPDIR;
                closedir APPDIR;
                if (!@apps)
                  {
                    error ("No application found at $appdir.");
                  }
                foreach my $app (@apps)
                  {
                    my $resdir = "$appdir/$app/Resources";
                    my $desktop = $app;

                    # Delete .desktop file generated by pl2link.
                    $desktop =~ s/\.app$/.desktop/g;
                    $desktop = "$resdir/$desktop";
                    unlink ($desktop);
                    verbose_print ("rm -f $desktop");

                    # Do the main job.
                    install_dir ("$pkgdir/$SHARE_ROOT/$app");
                    move ($resdir, "$pkgdir/$SHARE_ROOT/$app")
                      or die ("$package: move failed: $!");
                    verbose_print ("mv $resdir $pkgdir/$SHARE_ROOT/$app");
                    make_symlink ("$LIB_ROOT/Applications/$app/Resources",
                                  "/$SHARE_ROOT/$app", $tmp);

                    if ($dh{GAME})
                      {
                        my $files = 0;
                        my $executable = $app;
                        $executable =~ s/\.app$//g;

                        sub move_and_count
                        {
                          if (-l $_ && basename ($_) eq $executable)
                            {
                              move ($File::Find::name, "$pkgdir/usr/games")
                                or die ("$_: move failed: $!");
                              verbose_print ("mv $_ $pkgdir/usr/games");
                            }
                          $files += 1;
                        }

                        install_dir ("$pkgdir/usr/games");
                        find ({ wanted => \&move_and_count, no_chdir => 1 },
                              "$pkgdir/usr/bin");

                        if ($files < 2)
                          {
                            error ("No symlink found at $pkgdir/usr/bin.");
                          }

                        if (rmdir ("$pkgdir/usr/bin"))
                          {
                            verbose_print ("rmdir $pkgdir/usr/bin");
                          }
                      }
                    }

                  if ($dh{MOVE_TO})
                    {
                      if (package_is_arch_all ($package))
                        {
                          remove_tree ("$tmp/usr/lib");
                          verbose_print ("rm -rf $tmp/usr/lib");
                        }
                      $move_to_processed = 1;
                      verbose_print ("$package: --move-to processed for app.");
                    }
                }
              elsif (! -d $appdir && $dh{APP})
                {
                  error ("Directory $appdir does not exist.");
                }

              if (-d $appsupportdir && $dh{APPSUPPORT}
                  && $move_to_processed < 2)
                {
                  # Theoretically the package may contain more than
                  # one Application Support item.
                  opendir APPSUPPORTDIR, $appsupportdir;
                  my @items = grep !/^\./, readdir APPSUPPORTDIR;
                  closedir APPSUPPORTDIR;
                  if (!@items)
                    {
                      error ("No items found at $appsupportdir.");
                    }
                  foreach my $item (@items)
                    {
                      opendir ITEMDIR, "$appsupportdir/$item";
                      my @bundles = grep !/^\./, readdir ITEMDIR;
                      closedir ITEMDIR;
                      if (!@bundles)
                        {
                          error ("No bundles found at $appsupportdir/$item.");
                        }
                      install_dir ("$pkgdir/$SHARE_ROOT/$item");
                      foreach my $bundle (@bundles)
                        {
                          my $resdir = "$appsupportdir/$item/$bundle/Resources";
                          move ($resdir, "$pkgdir/$SHARE_ROOT/$item/$bundle")
                            or die "$package: move failed: $!";
                          verbose_print ("mv $resdir $pkgdir/$SHARE_ROOT/$item/$bundle");
                          make_symlink ("$LIB_ROOT/ApplicationSupport/$item/$bundle/Resources",
                                        "/$SHARE_ROOT/$item/$bundle", $tmp);
                        }
                    }
                  if ($dh{MOVE_TO})
                    {
                      if (package_is_arch_all ($package))
                        {
                          remove_tree ("$tmp/usr/lib");
                          verbose_print ("rm -rf $tmp/usr/lib");
                        }
                      $move_to_processed = 2;
                      verbose_print ("$package: --move-to processed for appsupport.");
                    }
                }
              elsif (! -d $appsupportdir && $dh{APPSUPPORT})
                {
                  error ("Directory $appsupportdir does not exist.");
                }

              if (-d $bundledir && ($dh{BUNDLE} || $dh{BUNDLE_DIR})
                  && $move_to_processed < 3)
                {
                  my $recurse = 0;
                  my $dir = $bundledir;

                  if (!$dh{MOVE_TO})
                    {
                      $dir =~ s/\Q$pkgdir\E\/\Q$LIB_ROOT\E\///;
                    }
                  else
                    {
                      $dir =~ s/debian\/tmp\/\Q$LIB_ROOT\E\///;
                    }

                  # Bundles can be installed directly under
                  # /usr/lib/GNUstep/Bundles or in a subdirectory; we
                  # have to figure it out.
                  opendir BUNDLEDIR, $bundledir;
                  my @items = grep !/^\./, readdir BUNDLEDIR;
                  closedir BUNDLEDIR;
                  if (!@items)
                    {
                      error ("No items found at $bundledir.");
                    }
                  foreach my $item (@items)
                    {
                      install_dir ("$pkgdir/$SHARE_ROOT/$item");
                      if (! -d "$bundledir/$item/Resources")
                        {
                          $recurse = 1;
                        }

                      if ($recurse)
                        {
                          opendir ITEMDIR, "$bundledir/$item";
                          my @bundles = grep !/^\./, readdir ITEMDIR;
                          closedir ITEMDIR;
                          if (!@bundles)
                            {
                              error ("No bundles found at $bundledir/$item.");
                            }
                          foreach my $bundle (@bundles)
                            {
                              my $resdir = "$bundledir/$item/$bundle/Resources";
                              move ($resdir, "$pkgdir/$SHARE_ROOT/$item/$bundle")
                                or die "$package: move failed: $!";
                              verbose_print ("mv $resdir $pkgdir/$SHARE_ROOT/$item/$bundle");
                              make_symlink ("$LIB_ROOT/$dir/$item/$bundle/Resources",
                                            "/$SHARE_ROOT/$item/$bundle", $tmp);
                            }
                        }
                      else
                        {
                          my $resdir = "$bundledir/$item/Resources";
                          move ($resdir, "$pkgdir/$SHARE_ROOT/$item")
                            or die "$package: move failed: $!";
                          verbose_print ("mv $resdir $pkgdir/$SHARE_ROOT/$item");
                          make_symlink ("$LIB_ROOT/$dir/$item/Resources",
                                        "/$SHARE_ROOT/$item", $tmp);
                        }
                    }
                  if ($dh{MOVE_TO})
                    {
                      if (package_is_arch_all ($package))
                        {
                          remove_tree ("$tmp/usr/lib");
                          verbose_print ("rm -rf $tmp/usr/lib");
                        }
                      $move_to_processed = 3;
                      verbose_print ("$package: --move-to processed for bundle.");
                    }
                }
              elsif (! -d $bundledir && ($dh{BUNDLE} || $dh{BUNDLE_DIR}))
                {
                  error ("Directory $bundledir does not exist.");
                }
            }
          }

    log_installed_files ($package, '');

    # Bug-script handling.
    if ($package =~ /\.app$/ || $dh{BUG_SCRIPT})
      {
        my $p_dir = "${tmp}/usr/share/bug";
        my $dir = "${p_dir}/$package";
        my $bugscript = "/usr/share/bug/gnustep-back-common";
        my $add_depends = 1;

        if (-f $dir || -f "${dir}/script")
          {
            warning ("Not installing bug script symlink for $package");
            warning ("because a bug script already exists.");
            $add_depends = 0;
          }
        elsif (! -d $dir)
          {
            install_dir ($p_dir);
            make_symlink ("/usr/share/bug/$package", $bugscript, $tmp);
          }
        else
          {
            make_symlink ("/usr/share/bug/$package/script", $bugscript, $tmp);
          }

        if ($add_depends)
          {
            addsubstvar ($package, "misc:Depends",
                         "gnustep-back-common", ">= 0.31.0-3");
          }
      }

    # Cleanup of build artifacts.
    if ($dh{NO_CLEANUP})
      {
        verbose_print ("Not performing cleanup for package $package");
        verbose_print ("because --no-cleanup was given.");
      }
    else
      {
        my $stamps = 0;
        my $deps = 0;

        sub delete_and_count
        {
          my $file = basename ($File::Find::name);

          if ($file eq "stamp.make" && -f $_)
            {
              if (unlink ($File::Find::name))
                {
                  verbose_print ("rm -f $_");
                  $stamps += 1;
                }
              else
                {
                  warning ("Could not delete $_: $!");
                }
            }
          elsif ($file eq "dependencies" && -f $_)
            {
              if (unlink ($File::Find::name))
                {
                  verbose_print ("rm -f $_");
                  $deps += 1;
                }
              else
                {
                  warning ("Could not delete $_: $!");
                }
            }
        }

        find ({ wanted => \&delete_and_count, no_chdir => 1 }, $tmp);

        if ($stamps == 1)
          {
            nonquiet_print ("Deleted 1 stamp.make file in $package.");
          }
        elsif ($stamps > 1)
          {
            nonquiet_print ("Deleted $stamps stamp.make files in $package.");
          }

        if ($deps == 1)
          {
            nonquiet_print ("Deleted 1 dependencies file in $package.");
          }
        elsif ($deps > 1)
          {
            nonquiet_print ("Deleted $deps dependencies files in $package.");
          }
      }

    # Make each package related to the GNUstep layout depend on the
    # virutal package gnustep-layout-multiarch (provided by the
    # gnustep-multiarch package).
    if (-d "$tmp/$LIB_ROOT" || -d "$tmp/$INCLUDE_ROOT")
      {
        addsubstvar ($package, "misc:Depends", "gnustep-layout-multiarch");
      }
  }

=head1 SEE ALSO

L<debhelper(7)>, L<dh_link(1)>, L<dh_bugfiles(1)>

This program is not part of debhelper.

=head1 AUTHORS

Hubert Chan <uhoreg@debian.org>

Yavor Doganov <yavor@gnu.org>

=cut
