[Git][haskell-team/haskell-devscripts][master] 5 commits: Move detection of missing executable nearer to the point of use.

Felix Lechner (@lechner) gitlab at salsa.debian.org
Sun Apr 3 11:00:54 BST 2022



Felix Lechner pushed to branch master at Debian Haskell Group / haskell-devscripts


Commits:
8ed04837 by Felix Lechner at 2022-04-02T21:48:27-07:00
Move detection of missing executable nearer to the point of use.

Reduces the functionality of Dh_Haskell.sh, a shell library, so it can be
replaced more easily by a Perl module.

The Perl module will accessible directly from Debhelper.

- - - - -
f1728c58 by Felix Lechner at 2022-04-02T21:48:45-07:00
Parse command line arguments in each script; export DH_EXCLUDES.

Reduces the functionality of Dh_Haskell.sh, a shell library, so it can be
replaced more easily by a Perl module.

The Perl module will be accessible directly from Debhelper.

- - - - -
e5228c9d by Felix Lechner at 2022-04-02T21:48:45-07:00
Add a .perltidyrc (from Lintian).

- - - - -
26b6cd41 by Felix Lechner at 2022-04-02T21:48:45-07:00
Add a .perlcriticrc (from Lintian).

- - - - -
8d20067a by Felix Lechner at 2022-04-03T01:37:37-07:00
Outsource all functions in Dh_Haskell.sh to a Perl module.

- - - - -


11 changed files:

- + .perlcriticrc
- + .perltidyrc
- Dh_Haskell.sh
- debian/control
- debian/haskell-devscripts-minimal.install
- dh_haskell_blurbs
- dh_haskell_depends
- dh_haskell_extra_depends
- dh_haskell_provides
- dh_haskell_shlibdeps
- + lib/Debian/Debhelper/Buildsystem/Haskell/Recipes.pm


Changes:

=====================================
.perlcriticrc
=====================================
@@ -0,0 +1,458 @@
+# -*- conf -*-
+# the list of checks could perhaps be moved to t/scripts/critic.pl.
+
+verbose = 1
+
+# severity is ignored for our main purposes, see below
+severity = 1
+
+criticism-fatal = 1
+color = 1
+allow-unsafe = 1
+
+# to try some other stuff, uncomment the following
+# theme = security || bugs || complexity || maintenance
+
+# use a whitelist; the disabling config blocks below are for documentation only
+only = 1
+
+# use separate blocks below instead of long Lines in include
+include =
+
+[BuiltinFunctions::ProhibitBooleanGrep]
+
+[BuiltinFunctions::ProhibitComplexMappings]
+
+[BuiltinFunctions::ProhibitLvalueSubstr]
+
+[BuiltinFunctions::ProhibitReverseSortBlock]
+
+[BuiltinFunctions::ProhibitShiftRef]
+
+[BuiltinFunctions::ProhibitSleepViaSelect]
+
+[BuiltinFunctions::ProhibitStringyEval]
+allow_includes = 1
+
+[BuiltinFunctions::ProhibitStringySplit]
+
+[BuiltinFunctions::ProhibitUniversalCan]
+
+[BuiltinFunctions::ProhibitUniversalIsa]
+
+[BuiltinFunctions::ProhibitUselessTopic]
+
+[BuiltinFunctions::ProhibitVoidGrep]
+
+[BuiltinFunctions::ProhibitVoidMap]
+
+[BuiltinFunctions::RequireBlockGrep]
+
+[BuiltinFunctions::RequireBlockMap]
+
+[BuiltinFunctions::RequireGlobFunction]
+
+[BuiltinFunctions::RequireSimpleSortBlock]
+
+[ClassHierarchies::ProhibitAutoloading]
+
+[ClassHierarchies::ProhibitExplicitISA]
+
+[ClassHierarchies::ProhibitOneArgBless]
+
+[-CodeLayout::ProhibitFatCommaNewline]
+
+[-CodeLayout::ProhibitIfIfSameLine]
+
+[CodeLayout::ProhibitHardTabs]
+
+[-CodeLayout::ProhibitParensWithBuiltins]
+
+[CodeLayout::ProhibitQuotedWordLists]
+
+[CodeLayout::ProhibitTrailingWhitespace]
+
+[-CodeLayout::RequireConsistentNewlines]
+
+[-CodeLayout::RequireFinalSemicolon]
+
+[CodeLayout::RequireTidyCode]
+
+[-CodeLayout::RequireTrailingCommaAtNewline]
+
+[-CodeLayout::RequireTrailingCommas]
+
+[ControlStructures::ProhibitCStyleForLoops]
+
+[-ControlStructures::ProhibitCascadingIfElse]
+
+[-ControlStructures::ProhibitDeepNests]
+
+[ControlStructures::ProhibitLabelsWithSpecialBlockNames]
+
+[ControlStructures::ProhibitMutatingListFunctions]
+
+[ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions]
+
+[-ControlStructures::ProhibitPostfixControls]
+
+[-ControlStructures::ProhibitUnlessBlocks]
+
+[ControlStructures::ProhibitUnreachableCode]
+
+[ControlStructures::ProhibitUntilBlocks]
+
+[ControlStructures::ProhibitYadaOperator]
+
+[-Compatibility::ConstantPragmaHash]
+
+[-Compatibility::ConstantLeadingUnderscore]
+
+[-Compatibility::Gtk2Constants]
+
+[-Compatibility::PerlMinimumVersionAndWhy]
+
+[-Compatibility::PodMinimumVersion]
+
+[-Compatibility::ProhibitUnixDevNull]
+
+[-Documentation::PodSpelling]
+
+[-Documentation::ProhibitAdjacentLinks]
+
+[Documentation::ProhibitDuplicateHeadings]
+
+[Documentation::ProhibitDuplicateSeeAlso]
+
+[Documentation::ProhibitBadAproposMarkup]
+
+[Documentation::ProhibitLinkToSelf]
+
+[Documentation::ProhibitParagraphEndComma]
+
+[Documentation::ProhibitParagraphTwoDots]
+
+[Documentation::ProhibitUnbalancedParens]
+
+[-Documentation::ProhibitVerbatimMarkup]
+
+[-Documentation::RequireEndBeforeLastPod]
+
+[-Documentation::RequireFilenameMarkup]
+
+[-Documentation::RequireFinalCut]
+
+[-Documentation::RequireLinkedURLs]
+
+[Documentation::RequirePackageMatchesPodName]
+
+[-Documentation::RequirePodAtEnd]
+
+[-Documentation::RequirePodSections]
+
+[-ErrorHandling::RequireCarping]
+
+[-ErrorHandling::RequireCheckingReturnValueOfEval]
+
+[Freenode::AmpersandSubCalls]
+
+[Freenode::ArrayAssignAref]
+
+[Freenode::BarewordFilehandles]
+
+[Freenode::ConditionalDeclarations]
+
+[Freenode::ConditionalImplicitReturn]
+
+[Freenode::DeprecatedFeatures]
+
+[Freenode::DiscouragedModules]
+
+[Freenode::DollarAB]
+
+[Freenode::Each]
+
+[Freenode::EmptyReturn]
+
+[Freenode::IndirectObjectNotation]
+
+[Freenode::LexicalForeachIterator]
+
+[Freenode::LoopOnHash]
+
+[-Freenode::ModPerl]
+
+[Freenode::MultidimensionalArrayEmulation]
+
+[Freenode::OpenArgs]
+
+[Freenode::OverloadOptions]
+
+[Freenode::PackageMatchesFilename]
+
+[Freenode::POSIXImports]
+
+[Freenode::PreferredAlternatives]
+
+[Freenode::Prototypes]
+
+[Freenode::StrictWarnings]
+
+[Freenode::Threads]
+
+[Freenode::Wantarray]
+
+[Freenode::WarningsSwitch]
+
+[Freenode::WhileDiamondDefaultAssignment]
+
+[InputOutput::ProhibitBacktickOperators]
+
+[InputOutput::ProhibitBarewordFileHandles]
+
+[-InputOutput::ProhibitExplicitStdin]
+
+[InputOutput::ProhibitInteractiveTest]
+
+[InputOutput::ProhibitJoinedReadline]
+
+[-InputOutput::ProhibitOneArgSelect]
+
+[InputOutput::ProhibitReadlineInForLoop]
+
+[-InputOutput::ProhibitTwoArgOpen]
+# not needed with Freenode::OpenArgs
+
+[InputOutput::RequireBracedFileHandleWithPrint]
+
+[-InputOutput::RequireBriefOpen]
+
+[-InputOutput::RequireCheckedClose]
+
+[-InputOutput::RequireCheckedOpen]
+
+[InputOutput::RequireCheckedSyscalls]
+functions = open opendir chdir read readdir readline closedir sysopen sysread sysclose mkdir link pipe readlink unlink rename symlink fork
+# possible TODO: close
+
+[-InputOutput::RequireEncodingWithUTF8Layer]
+
+[Miscellanea::ProhibitFormats]
+
+[-Miscellanea::ProhibitTies]
+
+[Miscellanea::ProhibitUnrestrictedNoCritic]
+
+[Miscellanea::ProhibitUselessNoCritic]
+
+[-Miscellanea::TextDomainPlaceholders]
+
+[-Miscellanea::TextDomainUnused]
+
+[Modules::ProhibitAutomaticExportation]
+
+[Modules::ProhibitConditionalUseStatements]
+
+[Modules::ProhibitEvilModules]
+
+[-Modules::ProhibitExcessMainComplexity]
+# Maybe some day...
+
+[Modules::ProhibitModuleShebang]
+
+[Modules::ProhibitMultiplePackages]
+
+[-Modules::ProhibitPOSIXimport]
+# not needed with Freenode::POSIXImports
+
+[Modules::ProhibitUseQuotedVersion]
+
+[Modules::RequireBarewordIncludes]
+
+[Modules::RequireEndWithOne]
+
+[Modules::RequireExplicitPackage]
+
+[-Modules::RequireFilenameMatchesPackage]
+# not needed with Freenode::PackageMatchesFilename
+
+[Modules::RequireNoMatchVarsWithUseEnglish]
+
+[-Modules::RequireVersionVar]
+# We don't use package versions atm and even if we did, it probably
+# won't have full coverage anyway.
+
+[NamingConventions::Capitalization]
+
+[NamingConventions::ProhibitAmbiguousNames]
+
+[Objects::ProhibitIndirectSyntax]
+
+[References::ProhibitDoubleSigils]
+
+[-RegularExpressions::ProhibitCaptureWithoutTest]
+
+[-RegularExpressions::ProhibitComplexRegexes]
+
+[-RegularExpressions::ProhibitEnumeratedClasses]
+
+[-RegularExpressions::ProhibitEscapedMetacharacters]
+
+[RegularExpressions::ProhibitFixedStringMatches]
+
+[RegularExpressions::ProhibitSingleCharAlternation]
+
+[RegularExpressions::ProhibitUnusedCapture]
+
+[RegularExpressions::ProhibitUnusualDelimiters]
+allow_all_brackets = 1
+
+[RegularExpressions::ProhibitUselessTopic]
+
+[RegularExpressions::RequireBracesForMultiline]
+allow_all_brackets = 1
+
+[-RegularExpressions::RequireDotMatchAnything]
+
+[-RegularExpressions::RequireExtendedFormatting]
+
+[-RegularExpressions::RequireLineBoundaryMatching]
+
+[-Subroutines::ProhibitAmpersandSigils]
+# not needed with Freenode::AmpersandSubCalls
+
+[Subroutines::ProhibitBuiltinHomonyms]
+
+[-Subroutines::ProhibitExcessComplexity]
+
+[-Subroutines::ProhibitExplicitReturnUndef]
+
+[-Subroutines::ProhibitManyArgs]
+
+[Subroutines::ProhibitNestedSubs]
+
+[Subroutines::ProhibitReturnSort]
+
+[-Subroutines::ProhibitSubroutinePrototypes]
+# not needed with Freenode::Prototypes
+
+[Subroutines::ProhibitUnusedPrivateSubroutines]
+
+[Subroutines::ProtectPrivateSubs]
+
+[Subroutines::RequireArgUnpacking]
+
+[Subroutines::RequireFinalReturn]
+terminal_funcs = CORE::exec fatal_error internal_error Lintian::Util::internal_error Die error
+
+[TestingAndDebugging::ProhibitNoStrict]
+
+[-TestingAndDebugging::ProhibitNoWarnings]
+
+[-TestingAndDebugging::ProhibitProlongedStrictureOverride]
+
+[-TestingAndDebugging::RequireTestLabels]
+
+[-TestingAndDebugging::RequireUseStrict]
+# not needed with Freenode::StrictWarnings]
+
+[-TestingAndDebugging::RequireUseWarnings]
+# not needed with Freenode::StrictWarnings]
+
+[ValuesAndExpressions::ConstantBeforeLt]
+
+[ValuesAndExpressions::NotWithCompare]
+
+[-ValuesAndExpressions::ProhibitArrayAssignAref]
+# not needed with Freenode::ArrayAssignAref
+
+[ValuesAndExpressions::ProhibitBarewordDoubleColon]
+
+[ValuesAndExpressions::ProhibitCommaSeparatedStatements]
+
+[-ValuesAndExpressions::ProhibitComplexVersion]
+
+[-ValuesAndExpressions::ProhibitConstantPragma]
+
+[ValuesAndExpressions::ProhibitDuplicateHashKeys]
+
+[ValuesAndExpressions::ProhibitEmptyCommas]
+
+[ValuesAndExpressions::ProhibitEmptyQuotes]
+
+[-ValuesAndExpressions::ProhibitEscapedCharacters]
+
+[ValuesAndExpressions::ProhibitFiletest_f]
+
+[ValuesAndExpressions::ProhibitImplicitNewlines]
+
+[ValuesAndExpressions::ProhibitInterpolationOfLiterals]
+
+[ValuesAndExpressions::ProhibitLeadingZeros]
+
+[ValuesAndExpressions::ProhibitLongChainsOfMethodCalls]
+
+[ValuesAndExpressions::ProhibitMagicNumbers]
+
+[ValuesAndExpressions::ProhibitMismatchedOperators]
+
+[ValuesAndExpressions::ProhibitMixedBooleanOperators]
+
+[ValuesAndExpressions::ProhibitNoisyQuotes]
+
+[ValuesAndExpressions::ProhibitNullStatements]
+
+[ValuesAndExpressions::ProhibitQuotesAsQuotelikeOperatorDelimiters]
+
+[ValuesAndExpressions::ProhibitSpecialLiteralHeredocTerminator]
+
+[ValuesAndExpressions::ProhibitUnknownBackslash]
+
+[-ValuesAndExpressions::ProhibitVersionStrings]
+
+[-ValuesAndExpressions::RequireConstantVersion]
+
+[-ValuesAndExpressions::RequireInterpolationOfMetachars]
+
+[ValuesAndExpressions::RequireNumberSeparators]
+
+[-ValuesAndExpressions::RequireNumericVersion]
+
+[ValuesAndExpressions::RequireQuotedHeredocTerminator]
+
+[ValuesAndExpressions::RequireUpperCaseHeredocTerminator]
+
+[ValuesAndExpressions::UnexpandedSpecialLiteral]
+
+[Variables::ProhibitAugmentedAssignmentInDeclaration]
+
+[Variables::ProhibitConditionalDeclarations]
+
+[-Variables::ProhibitEvilVariables]
+
+[-Variables::ProhibitLocalVars]
+
+[Variables::ProhibitMatchVars]
+
+[Variables::ProhibitPackageVars]
+add_packages = Devel::Size Module::CoreList Text::Glob Text::Wrap YAML::XS
+
+[Variables::ProhibitPerl4PackageNames]
+
+[-Variables::ProhibitPunctuationVars]
+# Requires "use English" and our style is against that.
+
+[Variables::ProhibitReusedNames]
+
+[Variables::ProhibitUnusedVariables]
+
+[Variables::ProtectPrivateVars]
+
+[Variables::RequireInitializationForLocalVars]
+
+[Variables::RequireLexicalLoopIterators]
+
+[Variables::RequireLocalizedPunctuationVars]
+allow = %ENV %SIG $! $? $0
+
+[Variables::RequireNegativeIndices]


=====================================
.perltidyrc
=====================================
@@ -0,0 +1,19 @@
+# -*- conf -*-
+#
+# Default options for perltidy for proper Perl code reformatting.
+#
+# This file is based on the one from the rra-c-util package,
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
+
+-bbao           # put line breaks before any operator
+-nbbc           # don't force blank lines before comments (bad for else blocks)
+-ce             # cuddle braces around else
+-l=79           # usually use 78, but don't want 79-long lines reformatted
+-pt=2           # don't add extra whitespace around parentheses
+-sbt=2          # ...or square brackets
+-sfs            # no space before semicolon in for (not that I use this form)
+-bar            # opening-brace-always-on-right
+-sot            # avoid lines with isolated opening tokens
+-sct            # ... same for closing tokens
+-fs             # allow "perltidy, please don't touch this" sections
+-fws            # don't add or delete whitespace


=====================================
Dh_Haskell.sh
=====================================
@@ -1,706 +1,193 @@
+recipe(){
+    local -x RECIPE="$1"
+    shift
+    perl -d:Confess \
+         -MDebian::Debhelper::Buildsystem::Haskell::Recipes=/.*/ \
+         -MUnicode::UTF8=decode_utf8,encode_utf8 \
+         -E 'my @decoded = map { decode_utf8($_) } @ARGV; my @results = $ENV{RECIPE}->(@decoded); my $output = join(q{ }, @results); say encode_utf8($output) if length $output;' "$@" \
+        || exit
+}
+
 run () {
-  set -eo pipefail
-  echo -n "Running" >&2
-  printf " %q" "$@" >&2
-  echo              >&2
-  "$@"
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 cpu(){
-  set -eo pipefail
-  ghc -e 'putStr System.Info.arch'
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 os(){
-  set -eo pipefail
-  ghc -e 'putStr System.Info.os'
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 ghcjs_version(){
-  set -eo pipefail
-  ghcjs --numeric-ghcjs-version
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 ghcjs_ghc_version(){
-  set -eo pipefail
-  ghcjs --numeric-ghc-version
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 package_prefix(){
-    set -eo pipefail
-    echo $1 | sed -n -e 's|^\([^-]*\)-.*-[^-]*$|\1|p'
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 package_hc(){
-    set -eo pipefail
-    case $1 in
-        ghc|ghc-prof) echo "ghc";;
-        *) echo $1 | sed -n -e 's|^lib\([^-]*\)-.*-[^-]*$|\1|p';;
-    esac
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 package_ext(){
-    set -eo pipefail
-    case $1 in
-        # I'm told the ghc build uses these scripts, hence these special cases
-        ghc) echo "dev";;
-        ghc-prof) echo "prof";;
-        *) echo $1 | sed -n -e 's|^[^-]*-.*-\([^-]*\)$|\1|p';;
-    esac
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 packages_hc(){
-    set -eo pipefail
-    hcs=`{ for i in ${DEB_PACKAGES}; do package_hc $i; done; } | LC_ALL=C sort -u`
-    if [ `echo ${hcs} | wc -w` = 0 ]; then hcs=${DEB_DEFAULT_COMPILER}; fi
-    if [ `echo ${hcs} | wc -w` != 1 ]; then echo "Multiple compilers not supported: ${hc}"; exit 1; fi
-    echo ${hcs}
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 hc_libdir(){
-    set -eo pipefail
-    case $1 in
-      ghc) echo "usr/lib/haskell-packages/ghc/lib";;
-      ghcjs) echo "usr/lib/ghcjs/.cabal/lib";;
-      *) echo "Don't know package_libdir for $1" >&2; exit 1;;
-    esac
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 package_libdir(){
-    set -eo pipefail
-    hc_libdir `package_hc $1`
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 hc_pkgdir(){
-    set -eo pipefail
-    case $1 in
-        ghc) echo "var/lib/ghc/package.conf.d";;
-        ghcjs) echo "usr/lib/ghcjs/.ghcjs/`cpu`-`os`-`ghcjs_version`-`ghcjs_ghc_version`/ghcjs/package.conf.d";;
-        *) echo "Don't know pkgdir for $1" >&2; exit 1;;
-    esac
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 package_pkgdir(){
-    set -eo pipefail
-    hc_pkgdir `package_hc $1`
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 hc_prefix(){
-    set -eo pipefail
-    case $1 in
-      ghc) echo "usr";;
-      ghcjs) echo "usr/lib/ghcjs";;
-      *) echo "Don't know prefix for compiler $1" >&2; exit 1;;
-    esac
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 hc_haddock(){
-    set -eo pipefail
-    case $1 in
-        ghc) echo "haddock";;
-        ghcjs) echo "haddock-ghcjs";;
-        *) echo "Don't know pkgdir for $1" >&2; exit 1;;
-    esac
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 hc_docdir(){
-    set -eo pipefail
-    hc=$1
-    pkgid=$2
-    echo "usr/lib/${hc}-doc/haddock/${pkgid}/"
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 hc_htmldir(){
-    set -eo pipefail
-    hc=$1
-    CABAL_PACKAGE=$2
-    echo "usr/share/doc/lib${hc}-${CABAL_PACKAGE}-doc/html/"
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 hc_hoogle(){
-    set -eo pipefail
-    local hc
-    hc=$1
-    echo "/usr/lib/${hc}-doc/hoogle/"
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 strip_hash(){
-    set -eo pipefail
-    echo "$1" | sed 's/-................................$//'
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 sort_uniq(){
-    set -eo pipefail
-    {
-        for i in "$@" ; do
-            echo $i
-        done
-    } | LC_ALL=C sort -u | tr "\n" " "
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 dependency(){
-    set -eo pipefail
-    local package
-    local version
-    local next_upstream_version
-    package=$1
-    version=`dpkg-query --showformat='${Version}' -W $package`
-    next_upstream_version=`echo $version | sed  -e 's/-[^-]*$//' -e 's/$/+/'`
-    echo "$package (>= $version), $package (<< $next_upstream_version)"
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 ghc_pkg_field(){
-    set -eo pipefail
-    hc=$1
-    pkg=$2
-    field=$3
-    ${hc}-pkg --global field ${pkg} ${field} | head -n1
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 providing_package_for_ghc(){
-    set -eo pipefail
-    local package
-    local dep
-    local dir
-    local dirs
-    local lib
-    local hc
-    local ghcversion=`dpkg-query --showformat '${Version}' --show ghc`
-    hc=$1
-    if dpkg --compare-versions "${ghcversion}" '>=' 8
-    then
-        dep=$2
-    else
-        dep=`strip-hash $2`
-    fi
-    dirs=`ghc_pkg_field $hc $dep library-dirs | grep -i ^library-dirs | cut -d':' -f 2`
-    lib=`ghc_pkg_field $hc $dep hs-libraries | grep -i ^hs-libraries |  sed -e 's|hs-libraries: *\([^ ]*\).*|\1|' `
-    for dir in $dirs ; do
-        if [ -e "${dir}/lib${lib}.a" ] ; then
-            package=`dpkg-query -S ${dir}/lib${lib}.a | cut -d':' -f 1`
-            continue
-        fi
-    done
-    echo $package
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 providing_package_for_ghc_prof(){
-    set -eo pipefail
-    local package
-    local dep
-    local dir
-    local dirs
-    local lib
-    local hc
-    local ghcversion=`dpkg-query --showformat '${Version}' --show ghc`
-    hc=$1
-    if dpkg --compare-versions "${ghcversion}" '>=' 8
-    then
-        dep=$2
-    else
-        dep=`strip-hash $2`
-    fi
-    dirs=`ghc_pkg_field $hc $dep library-dirs | grep -i ^library-dirs | cut -d':' -f 2`
-    lib=`ghc_pkg_field $hc $dep hs-libraries | grep -i ^hs-libraries | sed -e 's|hs-libraries: *\([^ ]*\).*|\1|' `
-    for dir in $dirs ; do
-        if [ -e "${dir}/lib${lib}_p.a" ] ; then
-            package=`dpkg-query -S ${dir}/lib${lib}_p.a | cut -d':' -f 1`
-            continue
-        fi
-    done
-    echo $package
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 cabal_package_ids(){
-    set -eo pipefail
-    local pkg
-    local package_ids
-    local ghcpkg
-    ghcpkg="`tmp_package_db $@`"
-    until [ -z "$1" ]
-    do
-      pkg="`basename "$1" .conf`"
-      package_ids="$package_ids `${ghcpkg} --simple-output field "${pkg}" id`"
-      shift
-    done
-    echo $package_ids
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 cabal_depends(){
-    set -eo pipefail
-    local pkg
-    local dep
-    local depends
-    local final_depends
-    local ghcpkg
-    ghcpkg="`tmp_package_db $@`"
-    until [ -z "$1" ]
-    do
-      pkg="`basename "$1" .conf`"
-      depends="$depends `${ghcpkg} --simple-output field "${pkg}" depends`"
-      shift
-    done
-    for dep in `sort_uniq $depends` ; do
-        # The package is not mentioned in the ignored package list with the same version
-        # or mentioned without any version in the ignored package list?
-        if  echo " $ignores " | grep -qv " $dep " &&
-            echo " $ignores " | grep -qv " `echo $dep | sed s%-[0-9][.0-9a-zA-Z]*$%%` " ;
-        then
-            final_depends="$final_depends $dep"
-        fi
-    done
-    echo $final_depends
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 hashed_dependency(){
-    set -eo pipefail
-    local hc
-    local type
-    local pkgid
-    local virpkg
-    local ghcpkg
-    hc=$1
-    type=$2
-    pkgid=$3
-    ghcpkg="`usable_ghc_pkg`"
-    virtual_pkg=`package_id_to_virtual_package "${hc}" "$type" $pkgid "${ghcpkg}"`
-    # As a transition measure, check if dpkg knows about this virtual package
-    if dpkg-query -W $virtual_pkg >/dev/null 2>/dev/null;
-    then
-         echo $virtual_pkg
-    fi
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 depends_for_ghc(){
-    set -eo pipefail
-    local dep
-    local packages
-    local pkgid
-    local hc
-    hc=$1
-    shift
-    for pkgid in `cabal_depends $@` ; do
-        dep=`hashed_dependency ${hc} dev $pkgid`
-        if [ -z "$dep" ]
-        then
-          pkg=`providing_package_for_ghc $hc $pkgid`
-          if [ -n "$pkg" ]
-          then
-              dep=`dependency $pkg`
-              packages="$packages, $dep"
-          else
-              echo "WARNING: No Debian package provides haskell package $pkgid." >&2
-          fi
-        else
-            packages="$packages, $dep"
-        fi
-    done
-
-    echo $packages | sed -e 's/^,[ ]*//'
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 depends_for_ghc_prof(){
-    set -eo pipefail
-    local dep
-    local packages
-    local pkgid
-    local hc
-    hc=$1
-    shift
-    for pkgid in `cabal_depends $@` ; do
-        dep=`hashed_dependency ${hc} prof $pkgid`
-        if [ -z "$dep" ]
-        then
-          pkg=`providing_package_for_ghc_prof $hc $pkgid`
-          if [ -n "$pkg" ]
-          then
-              dep=`dependency $pkg`
-              packages="$packages, $dep"
-          else
-              echo "WARNING: No Debian package provides haskell package $pkgid." >&2
-          fi
-        else
-            packages="$packages, $dep"
-        fi
-    done
-
-    echo $packages | sed -e 's/^,[ ]*//'
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 usable_ghc_pkg() {
-    set -eo pipefail
-    local ghcpkg
-    local version
-    if [ -x inplace/bin/ghc-pkg ]
-    then
-        # We are building ghc and need to use the new ghc-pkg
-        ghcpkg="inplace/bin/ghc-pkg"
-        version="`dpkg-parsechangelog -S Version`"
-    else
-        ghcpkg="ghc-pkg"
-        version="`dpkg-query --showformat '${Version}' --show ghc`"
-    fi
-    # ghc-pkg prior to version 8 is unusable for our purposes.
-    if dpkg --compare-versions "$version" '>=' 8
-    then
-        echo "${ghcpkg}"
-    fi
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 tmp_package_db() {
-    set -eo pipefail
-    local ghcpkg
-    ghcpkg="`usable_ghc_pkg`"
-    if [ -n "${ghcpkg}" ]
-    then
-        if [ ! -f debian/tmp-db/package.cache ]
-        then
-            mkdir debian/tmp-db
-            cp $@ debian/tmp-db/
-            # Silence GHC 8.4's "ignoring (possibly broken) abi-depends field
-            # for packages" warning. See also, https://ghc.haskell.org/trac/ghc/ticket/14381
-            $ghcpkg --package-db debian/tmp-db/ recache >/dev/null
-        fi
-        echo "${ghcpkg} --package-db debian/tmp-db"
-    fi
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 provides_for_ghc(){
-    set -eo pipefail
-    local hc
-    local dep
-    local packages
-    hc=$1
-    shift
-    ghcpkg="`tmp_package_db $@`"
-    for package_id in `cabal_package_ids $@` ; do
-        packages="$packages, `package_id_to_virtual_package "${hc}" dev $package_id "${ghcpkg}"`"
-    done
-    echo $packages | sed -e 's/^,[ ]*//'
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 provides_for_ghc_prof(){
-    set -eo pipefail
-    local hc
-    local dep
-    local packages
-    hc=$1
-    shift
-    ghcpkg="`tmp_package_db $@`"
-    for package_id in `cabal_package_ids $@` ; do
-        packages="$packages, `package_id_to_virtual_package "${hc}" prof $package_id "${ghcpkg}"`"
-    done
-    echo $packages | sed -e 's/^,[ ]*//'
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 package_id_to_virtual_package(){
-        set -eo pipefail
-        local hc
-        local type
-        local pkgid
-        local ghcpkg
-        hc="$1"
-        type="$2"
-        pkgid="$3"
-        ghcpkg="$4"
-        if [ -n "$ghcpkg" ]
-        then
-            name=`${ghcpkg} --simple-output --unit-id field "${pkgid}" name`
-            version=`${ghcpkg} --simple-output --unit-id field "${pkgid}" version`
-            abi=`${ghcpkg} --simple-output --unit-id field "${pkgid}" abi | cut -c1-5`
-            echo "lib${hc}-${name}-${type}-${version}-${abi}" | tr A-Z a-z
-        else
-            # We don't have a usable ghc-pkg, so we fall back to parsing the package id.
-            echo ${pkgid} | tr A-Z a-z | \
-                grep '[a-z0-9]\+-[0-9\.]\+-................................' | \
-                perl -pe 's/([a-z0-9-]+)-([0-9\.]+)-(.....).........................../lib'${hc}'-\1-'$type'-\2-\3/'
-        fi
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 depends_for_hugs(){
-    set -eo pipefail
-    local version
-    local upstream_version
-    version=`dpkg-query --showformat='${Version}' -W hugs`
-    upstream_version=`echo $version | sed -e 's/-[^-]*$//'`
-    echo "hugs (>= $upstream_version)"
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 find_config_for_ghc(){
-    set -eo pipefail
-    local f
-    local pkg
-    pkg=$1
-    pkgdir=`package_pkgdir ${pkg}`
-    case "$pkg" in
-        ghc-prof)
-            pkg=ghc
-            ;;
-        *-prof)
-            pkg=`echo $pkg | sed -e 's/-prof$/-dev/'`
-            ;;
-        *)
-            ;;
-    esac
-    for f in debian/$pkg/${pkgdir}/*.conf ; do
-        if [ -f "$f" ] ; then
-            echo $f
-            echo " "
-        fi
-    done
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 clean_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + clean_recipe> "; set -x
-    [ ! -x "${DEB_SETUP_BIN_NAME}" ] || run ${DEB_SETUP_BIN_NAME} clean
-    run rm -rf dist dist-ghc dist-ghcjs dist-hugs ${DEB_SETUP_BIN_NAME} Setup.hi Setup.ho Setup.o .*config*
-    run rm -f configure-ghc-stamp configure-ghcjs-stamp build-ghc-stamp build-ghcjs-stamp build-hugs-stamp build-haddock-stamp
-    run rm -rf debian/tmp-inst-ghc debian/tmp-inst-ghcjs
-    run rm -f debian/extra-depends-ghc debian/extra-depends-ghcjs
-    if [ -f ${DEB_LINTIAN_OVERRIDES_FILE} ] ; then
-      run sed -i '/binary-or-shlib-defines-rpath/ d' ${DEB_LINTIAN_OVERRIDES_FILE}
-      run find ${DEB_LINTIAN_OVERRIDES_FILE} -empty -delete;
-    fi
-
-    run rm -f ${MAKEFILE}
-    run rm -rf debian/dh_haskell_shlibdeps
-    run rm -rf debian/tmp-db
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 make_setup_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + make_setup_recipe> "; set -x
-    for setup in Setup.lhs Setup.hs
-    do
-      if test -e $setup
-      then
-        run ghc --make $setup -o ${DEB_SETUP_BIN_NAME}
-        exit 0
-      fi
-    done
-    # Having a Setup.hs is considered good practice, but there are a few
-    # Haskell packages that don't, since cabal does not use it for build types
-    # other than 'Custom'. Find out the build type and use the corresponding
-    # standardized Setup.hs file. For more information, see
-    # https://www.haskell.org/cabal/users-guide/developing-packages.html#pkg-field-build-type
-    if grep -qi '^build-type: \+Simple' ${CABAL_PACKAGE}.cabal; then
-        setup="/usr/share/haskell-devscripts/Setup-Simple.hs"
-    elif grep -qi 'build-type: \+Configure' ${CABAL_PACKAGE}.cabal; then
-        setup="/usr/share/haskell-devscripts/Setup-Configure.hs"
-    elif grep -qi 'build-type: \+Make' ${CABAL_PACKAGE}.cabal; then
-        setup="/usr/share/haskell-devscripts/Setup-Make.hs"
-    else
-        echo "Could not find a suitable Setup.hs file" >&2
-        exit 1
-    fi
-    run ghc --make $setup -o ${DEB_SETUP_BIN_NAME} -outputdir debian/tmp-setup-hs
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 configure_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + configure_recipe> "; set -x
-
-    # dak gets all neurotic about file timestamps older than 1975
-    # new tarballs from Hackage have files with mtimes at the
-    # beginning of the epoch, so work around this pair of silliness
-    # by setting old mtimes to 1998
-    reftime=$(mktemp)
-    touch -d "1975-01-01 UTC" "${reftime}"
-    find . \! -newer "${reftime}" -exec touch -d "1998-01-01 UTC" {} \;
-    rm "${reftime}"
-
-    hc=`packages_hc`
-
-    ENABLE_PROFILING=""
-    for i in ${DEB_PACKAGES}; do
-        pkg_ext="`package_ext $i`"
-        if [ "$pkg_ext" == "prof" ]; then
-            ENABLE_PROFILING="--enable-library-profiling"
-            break
-        fi
-    done
-    local GHC_OPTIONS
-    for i in `dpkg-buildflags --get LDFLAGS`
-    do
-        GHC_OPTIONS="$GHC_OPTIONS --ghc-option=-optl$i"
-    done
-
-    # DEB_SETUP_GHC_CONFIGURE_ARGS can contain multiple arguments with their own quoting,
-    # so run this through eval
-    eval run ${DEB_SETUP_BIN_NAME} \
-        configure "--${hc}" \
-        -v2 \
-        --package-db=/`hc_pkgdir ${hc}` \
-        --prefix=/`hc_prefix ${hc}` \
-        --libdir=/`hc_libdir ${hc}` \
-        --libexecdir=/usr/lib \
-        --builddir=dist-${hc} \
-        ${GHC_OPTIONS} \
-        --haddockdir=/`hc_docdir ${hc} ${CABAL_PACKAGE}-${CABAL_VERSION}` \
-        --datasubdir=${CABAL_PACKAGE}\
-        --htmldir=/`hc_htmldir ${hc} ${CABAL_PACKAGE}` \
-        ${ENABLE_PROFILING} \
-        ${NO_GHCI_FLAG} \
-        ${DEB_SETUP_GHC6_CONFIGURE_ARGS} \
-        ${DEB_SETUP_GHC_CONFIGURE_ARGS} \
-        ${OPTIMIZATION} \
-        ${TESTS}
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 build_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + build_recipe> "; set -x
-    hc=`packages_hc`
-    run ${DEB_SETUP_BIN_NAME} build --builddir=dist-${hc}
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 check_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + check_recipe> "; set -x
-    hc=`packages_hc`
-    run ${DEB_SETUP_BIN_NAME} test --builddir=dist-${hc} --show-details=direct
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 haddock_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + haddock_recipe> "; set -x
-    hc=`packages_hc`
-    haddock=`hc_haddock ${hc}`
-    if [ -x /usr/bin/${haddock} ] && \
-          ! run ${DEB_SETUP_BIN_NAME} haddock --builddir=dist-${hc} --with-haddock=/usr/bin/${haddock} --with-ghc=${hc} --verbose=2 ${DEB_HADDOCK_OPTS} ; then
-       echo "Haddock failed (no modules?), refusing to create empty documentation package."
-       exit 1
-    fi
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 extra_depends_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + extra_depends_recipe> "; set -x
-    hc=$1
-    pkg_config=$(LC_ALL=C.UTF-8 ${DEB_SETUP_BIN_NAME} register --builddir=dist-${hc} --gen-pkg-config --verbose=verbose+nowrap | sed -r -n '/^Creating package registration file: /s///p')
-    run dh_haskell_extra_depends ${hc} $pkg_config
-    rm $pkg_config
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 install_dev_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + install_dev_recipe> "; set -x
-    PKG=$1
-
-    hc=`package_hc ${PKG}`
-    libdir=`package_libdir ${PKG}`
-    pkgdir=`package_pkgdir ${PKG}`
-
-    ( run cd debian/tmp-inst-${hc} ; run mkdir -p ${libdir} ; run find ${libdir}/ \
-        \( ! -name "*_p.a" ! -name "*.p_hi" ! -type d \) \
-        -exec install -Dm 644 '{}' ../${PKG}/'{}' ';' )
-    pkg_config=$(LC_ALL=C.UTF-8 ${DEB_SETUP_BIN_NAME} register --builddir=dist-${hc} --gen-pkg-config --verbose=verbose+nowrap | sed -r -n '/^Creating package registration file: /s///p')
-    if [ "${HASKELL_HIDE_PACKAGES}" ]; then sed -i 's/^exposed: True$/exposed: False/' $pkg_config; fi
-    run install -Dm 644 $pkg_config debian/${PKG}/${pkgdir}/$pkg_config
-    run rm -f $pkg_config
-    if [ "z${DEB_GHC_EXTRA_PACKAGES}" != "z" ] ; then
-       EP_DIR=debian/${PKG}/usr/lib/haskell-packages/extra-packages
-       run mkdir -p $EP_DIR
-       echo "${DEB_GHC_EXTRA_PACKAGES}" > ${EP_DIR}/${CABAL_PACKAGE}-${CABAL_VERSION}
-    fi
-
-    grep -s binary-or-shlib-defines-rpath ${DEB_LINTIAN_OVERRIDES_FILE} \
-       || echo binary-or-shlib-defines-rpath >> ${DEB_LINTIAN_OVERRIDES_FILE}
-    run dh_haskell_provides -p${PKG}
-    run dh_haskell_depends -p${PKG}
-    run dh_haskell_shlibdeps -p${PKG}
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 install_prof_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + install_prof_recipe> "; set -x
-    PKG=$1
-    libdir=`package_libdir ${PKG}`
-    ( run cd debian/tmp-inst-`package_hc ${PKG}`
-      run mkdir -p ${libdir}
-      run find ${libdir}/ \
-        ! \( ! -name "*_p.a" ! -name "*.p_hi" \) \
-        -exec install -Dm 644 '{}' ../${PKG}/'{}' ';' )
-    run dh_haskell_provides -p${PKG}
-    run dh_haskell_depends -p${PKG}
-    # PS4=$PS5
+    recipe "${FUNCNAME[0]}" "$@"
 }
 
 install_doc_recipe(){
-    set -eo pipefail
-    # local PS5=$PS4; PS4=" + install_doc_recipe> "; set -x
-    PKG=$1
-    hc=`package_hc ${PKG}`
-    pkgid=${CABAL_PACKAGE}-${CABAL_VERSION}
-    docdir=`hc_docdir ${hc} ${pkgid}`
-    htmldir=`hc_htmldir ${hc} ${CABAL_PACKAGE}`
-    hoogle=`hc_hoogle ${hc}`
-    run mkdir -p debian/${PKG}/${htmldir}
-    ( run cd debian/tmp-inst-${hc}/ ;
-      run find ./${htmldir} \
-        ! -name "*.haddock" ! -type d -exec install -Dm 644 '{}' \
-        ../${PKG}/'{}' ';' )
-    run mkdir -p debian/${PKG}/${docdir}
-    [ 0 = `ls debian/tmp-inst-${hc}/${docdir}/ 2>/dev/null | wc -l` ] ||
-        run cp -r debian/tmp-inst-${hc}/${docdir}/*.haddock debian/${PKG}/${docdir}
-    if [ "${DEB_ENABLE_HOOGLE}" = "yes" ]
-    then
-        # We cannot just invoke dh_link here because that acts on
-        # either libghc-*-dev or all the binary packages, neither of
-        # which is desirable (see dh_link (1)).  So we just create a
-        # (policy-compliant) symlink ourselves
-        source="debian/${PKG}/${htmldir}/${CABAL_PACKAGE}.txt"
-        dest=debian/${PKG}${hoogle}${PKG}.txt
-        if [ -f ${source} ]; then
-            run mkdir -p `dirname $dest`
-            run ln -rs -T $source $dest
-        fi
-    fi
-    run dh_haskell_depends -p${PKG}
-    # PS4=$PS5
-}
-
-if ! command -v grep-dctrl > /dev/null; then
-    echo "grep-dctrl is missing" >&2
-    exit 1
-fi
-
-args=
-ignores=
-files=
-until [ -z "$1" ]
-do
-  case "$1" in
-      -X*)
-          pkg=${1##-X}
-          ignores="$ignores $pkg"
-          ;;
-
-      --exclude=*)
-          pkg=${1##--exclude=}
-          ignores="$ignores $pkg"
-          ;;
-
-      -*)
-          args="$args $1"
-          ;;
-      *)
-          if [ -f $1 ] ; then
-              files="$files $1"
-          else
-              echo "Installed package description file $1 can not be found" >&2
-              exit 1
-          fi
-          ;;
-  esac
-  shift
-done
+    recipe "${FUNCNAME[0]}" "$@"
+}


=====================================
debian/control
=====================================
@@ -22,6 +22,12 @@ Depends: dctrl-tools
   , ${misc:Depends}
   , html-xml-utils
   , ghc-haddock
+  , libconst-fast-perl
+  , libdatetime-perl
+  , libipc-run3-perl
+  , liblist-someutils-perl
+  , libpath-tiny-perl
+  , libunicode-utf8-perl
 Breaks: haskell-devscripts (<= 0.10.2.3)
 Replaces: haskell-devscripts (<= 0.10.2.3)
 Suggests: haskell-devscripts


=====================================
debian/haskell-devscripts-minimal.install
=====================================
@@ -5,6 +5,7 @@ dh_haskell_extra_depends  usr/bin/
 dh_haskell_blurbs         usr/bin/
 Dh_Haskell.sh             usr/share/haskell-devscripts/
 hlibrary.mk               usr/share/cdbs/1/class
+lib/*                     usr/share/perl5/
 Setup-Make.hs             usr/share/haskell-devscripts/
 Setup-Simple.hs           usr/share/haskell-devscripts/
 Setup-Configure.hs        usr/share/haskell-devscripts/


=====================================
dh_haskell_blurbs
=====================================
@@ -6,10 +6,48 @@
 
 set -e 
 
+. /usr/share/haskell-devscripts/Dh_Haskell.sh
+
 DEB_DEFAULT_COMPILER=$1
 shift
 
-. /usr/share/haskell-devscripts/Dh_Haskell.sh
+args=
+ignores=
+files=
+until [ -z "$1" ]
+do
+  case "$1" in
+      -X*)
+          pkg=${1##-X}
+          ignores="$ignores $pkg"
+          ;;
+
+      --exclude=*)
+          pkg=${1##--exclude=}
+          ignores="$ignores $pkg"
+          ;;
+
+      -*)
+          args="$args $1"
+          ;;
+      *)
+          if [ -f $1 ] ; then
+              files="$files $1"
+          else
+              echo "Installed package description file $1 can not be found" >&2
+              exit 1
+          fi
+          ;;
+  esac
+  shift
+done
+
+export DH_EXCLUDES="$ignores"
+
+if ! command -v grep-dctrl > /dev/null; then
+    echo "grep-dctrl is missing" >&2
+    exit 1
+fi
 
 # PS4=" + dh_haskell_blurbs> "
 # set -x


=====================================
dh_haskell_depends
=====================================
@@ -56,6 +56,39 @@ set -e
 
 . /usr/share/haskell-devscripts/Dh_Haskell.sh
 
+args=
+ignores=
+files=
+until [ -z "$1" ]
+do
+  case "$1" in
+      -X*)
+          pkg=${1##-X}
+          ignores="$ignores $pkg"
+          ;;
+
+      --exclude=*)
+          pkg=${1##--exclude=}
+          ignores="$ignores $pkg"
+          ;;
+
+      -*)
+          args="$args $1"
+          ;;
+      *)
+          if [ -f $1 ] ; then
+              files="$files $1"
+          else
+              echo "Installed package description file $1 can not be found" >&2
+              exit 1
+          fi
+          ;;
+  esac
+  shift
+done
+
+export DH_EXCLUDES="$ignores"
+
 # PS4=" + dh_haskell_depends> "
 # set -x
 


=====================================
dh_haskell_extra_depends
=====================================
@@ -54,10 +54,43 @@
 
 set -e 
 
+. /usr/share/haskell-devscripts/Dh_Haskell.sh
+
 hc=$1
 shift
 
-. /usr/share/haskell-devscripts/Dh_Haskell.sh
+args=
+ignores=
+files=
+until [ -z "$1" ]
+do
+  case "$1" in
+      -X*)
+          pkg=${1##-X}
+          ignores="$ignores $pkg"
+          ;;
+
+      --exclude=*)
+          pkg=${1##--exclude=}
+          ignores="$ignores $pkg"
+          ;;
+
+      -*)
+          args="$args $1"
+          ;;
+      *)
+          if [ -f $1 ] ; then
+              files="$files $1"
+          else
+              echo "Installed package description file $1 can not be found" >&2
+              exit 1
+          fi
+          ;;
+  esac
+  shift
+done
+
+export DH_EXCLUDES="$ignores"
 
 # PS4=" + dh_haskell_extra_depends> "
 # set -x


=====================================
dh_haskell_provides
=====================================
@@ -62,6 +62,39 @@ else
         . /usr/share/haskell-devscripts/Dh_Haskell.sh
 fi
 
+args=
+ignores=
+files=
+until [ -z "$1" ]
+do
+  case "$1" in
+      -X*)
+          pkg=${1##-X}
+          ignores="$ignores $pkg"
+          ;;
+
+      --exclude=*)
+          pkg=${1##--exclude=}
+          ignores="$ignores $pkg"
+          ;;
+
+      -*)
+          args="$args $1"
+          ;;
+      *)
+          if [ -f $1 ] ; then
+              files="$files $1"
+          else
+              echo "Installed package description file $1 can not be found" >&2
+              exit 1
+          fi
+          ;;
+  esac
+  shift
+done
+
+export DH_EXCLUDES="$ignores"
+
 # PS4=" + dh_haskell_provides> "
 # set -x
 


=====================================
dh_haskell_shlibdeps
=====================================
@@ -27,6 +27,39 @@ set -e
 
 . /usr/share/haskell-devscripts/Dh_Haskell.sh
 
+args=
+ignores=
+files=
+until [ -z "$1" ]
+do
+  case "$1" in
+      -X*)
+          pkg=${1##-X}
+          ignores="$ignores $pkg"
+          ;;
+
+      --exclude=*)
+          pkg=${1##--exclude=}
+          ignores="$ignores $pkg"
+          ;;
+
+      -*)
+          args="$args $1"
+          ;;
+      *)
+          if [ -f $1 ] ; then
+              files="$files $1"
+          else
+              echo "Installed package description file $1 can not be found" >&2
+              exit 1
+          fi
+          ;;
+  esac
+  shift
+done
+
+export DH_EXCLUDES="$ignores"
+
 # PS4=" + dh_haskell_shlibdeps> "
 # set -x
 


=====================================
lib/Debian/Debhelper/Buildsystem/Haskell/Recipes.pm
=====================================
@@ -0,0 +1,1268 @@
+# Copyright © 2022 Felix Lechner <felix.lechner at lease-up.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, you can find it on the World Wide
+# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Debian::Debhelper::Buildsystem::Haskell::Recipes;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Exporter qw(import);
+
+our @EXPORT_OK;
+
+BEGIN {
+
+    @EXPORT_OK = qw(
+      run
+      cpu
+      os
+      ghcjs_version
+      ghcjs_ghc_version
+      package_prefix
+      package_hc
+      package_ext
+      packages_hc
+      hc_libdir
+      package_libdir
+      hc_pkgdir
+      package_pkgdir
+      hc_prefix
+      hc_haddock
+      hc_docdir
+      hc_htmldir
+      hc_hoogle
+      strip_hash
+      sort_uniq
+      dependency
+      ghc_pkg_field
+      providing_package_for_ghc
+      providing_package_for_ghc_prof
+      cabal_package_ids
+      cabal_depends
+      hashed_dependency
+      depends_for_ghc
+      depends_for_ghc_prof
+      usable_ghc_pkg
+      tmp_package_db
+      provides_for_ghc
+      provides_for_ghc_prof
+      package_id_to_virtual_package
+      depends_for_hugs
+      find_config_for_ghc
+      clean_recipe
+      make_setup_recipe
+      configure_recipe
+      build_recipe
+      check_recipe
+      haddock_recipe
+      extra_depends_recipe
+      install_dev_recipe
+      install_prof_recipe
+      install_doc_recipe
+    );
+}
+
+use Const::Fast;
+use Cwd;
+use Date::Parse qw(str2time);
+use File::Basename;
+use IPC::Run3;
+use List::SomeUtils qw(uniq any first_value);
+use Path::Tiny;
+use Unicode::UTF8 qw(encode_utf8 decode_utf8);
+
+const my $EMPTY => q{};
+const my $SPACE => q{ };
+const my $PLUS => q{+};
+const my $HYPHEN => q{-};
+const my $COMMA => q{,};
+const my $SEMICOLON => q{;};
+const my $LESS_THAN => q{<};
+const my $DOUBLE_LESS_THAN => $LESS_THAN x 2;
+const my $NEWLINE => qq{\n};
+
+const my $WAIT_STATUS_SHIFT => 8;
+
+const my $MINIMUM_GHC_VERSION => 8;
+const my $CABAL_VERSION_IMPLYING_SIMPLE_BUILDS => 2.2;
+
+=head1 NAME
+
+Debian::Debhelper::Buildsystem::Haskell::Recipes -- Recipes for the Haskell build system in Debhelper
+
+=head1 SYNOPSIS
+
+ Debian::Debhelper::Buildsystem::Haskell::Recipes;
+
+=head1 DESCRIPTION
+
+A library with recipes for the Haskell build system in Debhelper.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item run_quiet
+
+=cut
+
+sub run_quiet {
+    my (@command) = @_;
+
+    my @command_bytes = map { encode_utf8($_) } @command;
+
+    my $stdout_bytes;
+    my $stderr_bytes;
+    run3(\@command_bytes, \undef, \$stdout_bytes, \$stderr_bytes);
+
+    my $wait_status = $?;
+    my $exitcode = ($wait_status >> $WAIT_STATUS_SHIFT);
+
+    # already in UTF-8
+    die encode_utf8("Non-zero exit code $exitcode.")
+      . $NEWLINE
+      . $stdout_bytes
+      . $stderr_bytes
+      if $exitcode;
+
+    my $output = decode_utf8($stdout_bytes // $EMPTY);
+    chomp $output;
+
+    return $output;
+}
+
+=item run
+
+=cut
+
+sub run {
+    my (@command) = @_;
+
+    my @filtered = grep { length } @command;
+
+    say {*STDERR} encode_utf8("Running @filtered")
+      if !$ENV{DH_QUIET} || $ENV{DH_VERBOSE};
+
+    my $output = run_quiet(@filtered);
+
+    say {*STDERR} encode_utf8($output)
+      if !$ENV{DH_QUIET} || $ENV{DH_VERBOSE};
+
+    return $output;
+}
+
+=item cpu
+
+=cut
+
+sub cpu {
+    my () = @_;
+
+    my $output = run(qw{ghc -e}, 'putStr System.Info.arch');
+
+    return $output;
+}
+
+=item os
+
+=cut
+
+sub os {
+    my () = @_;
+
+    my $output = run(qw{ghc -e}, 'putStr System.Info.os');
+
+    return $output;
+}
+
+=item ghcjs_version
+
+=cut
+
+sub ghcjs_version {
+    my () = @_;
+
+    my $output = run(qw{ghcjs --numeric-ghcjs-version});
+
+    return $output;
+}
+
+=item ghcjs_ghc_version
+
+=cut
+
+sub ghcjs_ghc_version {
+    my () = @_;
+
+    my $output = run(qw{ghcjs --numeric-ghc-version});
+
+    return $output;
+}
+
+=item package_prefix
+
+=cut
+
+sub package_prefix {
+    my ($installable) = @_;
+
+    my $prefix = $installable;
+
+    # strip hackage name
+    $prefix =~ s{ - .* $}{}x;
+
+    return $prefix;
+}
+
+=item package_hc
+
+=cut
+
+sub package_hc {
+    my ($installable) = @_;
+
+    return 'ghc'
+      if $installable =~ m{^ ghc (:? -prof )? $};
+
+    my $compiler = $installable;
+
+    # strip hackage name
+    $compiler =~ s{ - .* $}{}x;
+
+    # strip lib prefix
+    $compiler =~ s{^ lib }{}x;
+
+    return $compiler;
+}
+
+=item package_ext
+
+=cut
+
+sub package_ext {
+    my ($installable) = @_;
+
+    return 'dev'
+      if $installable eq 'ghc';
+
+    return 'prof'
+      if $installable eq 'ghc-prof';
+
+    my $suffix = $installable;
+
+    # strip hackage name
+    $suffix =~ s{^ .* - }{}x;
+
+    return $suffix;
+}
+
+=item packages_hc
+
+=cut
+
+sub packages_hc {
+    my () = @_;
+
+    # fix sort order
+    local $ENV{LC_ALL} = 'C';
+
+    # should be in UTF-8
+    my @installables = split($SPACE, $ENV{DEB_PACKAGES} // $EMPTY);
+
+    my @compilers = uniq map { package_hc($_) } @installables;
+
+    die encode_utf8(
+        'Multiple compilers not supported: ' . join($SPACE, (sort @compilers)))
+      if @compilers > 1;
+
+    return $ENV{DEB_DEFAULT_COMPILER}
+      if !@compilers;
+
+    return $compilers[0];
+}
+
+=item hc_libdir
+
+=cut
+
+sub hc_libdir {
+    my ($compiler) = @_;
+
+    return 'usr/lib/haskell-packages/ghc/lib'
+      if $compiler eq 'ghc';
+
+    return 'usr/lib/ghcjs/.cabal/lib'
+      if $compiler eq 'ghcjs';
+
+    die encode_utf8("Don't know package_libdir for $compiler");
+}
+
+=item package_libdir
+
+=cut
+
+sub package_libdir {
+    my ($installable) = @_;
+
+    my $compiler = package_hc($installable);
+
+    return hc_libdir($compiler);
+}
+
+=item hc_pkgdir
+
+=cut
+
+sub hc_pkgdir {
+    my ($compiler) = @_;
+
+    return 'var/lib/ghc/package.conf.d'
+      if $compiler eq 'ghc';
+
+    if ($compiler eq 'ghcjs') {
+
+        my $quadruplet
+          = cpu()
+          . $HYPHEN
+          . os()
+          . $HYPHEN
+          . ghcjs_version()
+          . $HYPHEN
+          . ghcjs_ghc_version();
+
+        return "usr/lib/ghcjs/.ghcjs/$quadruplet/ghcjs/package.conf.d";
+    }
+
+    die encode_utf8("Don't know pkgdir for $compiler");
+}
+
+=item package_pkgdir
+
+=cut
+
+sub package_pkgdir {
+    my ($installable) = @_;
+
+    my $compiler = package_hc($installable);
+
+    return hc_pkgdir($compiler);
+}
+
+=item hc_prefix
+
+=cut
+
+sub hc_prefix {
+    my ($compiler) = @_;
+
+    return 'usr'
+      if $compiler eq 'ghc';
+
+    return 'usr/lib/ghcjs'
+      if $compiler eq 'ghcjs';
+
+    die encode_utf8("Don't know prefix for $compiler");
+}
+
+=item hc_haddock
+
+=cut
+
+sub hc_haddock {
+    my ($compiler) = @_;
+
+    return 'haddock'
+      if $compiler eq 'ghc';
+
+    return 'haddock-ghcjs'
+      if $compiler eq 'ghcjs';
+
+    die encode_utf8("Don't know haddock command for $compiler");
+}
+
+=item hc_docdir
+
+=cut
+
+sub hc_docdir {
+    my ($compiler, $hackage_name_version) = @_;
+
+    return "usr/lib/$compiler-doc/haddock/$hackage_name_version/";
+}
+
+=item hc_htmldir
+
+=cut
+
+sub hc_htmldir {
+    my ($compiler, $hackage_name) = @_;
+
+    $ENV{CABAL_PACKAGE} = $hackage_name;
+
+    return "usr/share/doc/lib$compiler-$hackage_name-doc/html/";
+}
+
+=item hc_hoogle
+
+=cut
+
+sub hc_hoogle {
+    my ($compiler) = @_;
+
+    return "/usr/lib/$compiler-doc/hoogle/";
+}
+
+=item strip_hash
+
+=cut
+
+sub strip_hash {
+    my ($with_hash) = @_;
+
+    my $without_hash = $with_hash;
+    $without_hash =~ s{ - [^-]{32} $}{}x;
+
+    return $without_hash;
+}
+
+=item sort_uniq
+
+=cut
+
+sub sort_uniq {
+    my (@items) = @_;
+
+    # fix sort order
+    local $ENV{LC_ALL} = 'C';
+
+    my @sorted = sort +uniq @items;
+
+    return @sorted;
+}
+
+=item dependency
+
+=cut
+
+sub dependency {
+    my ($installable) = @_;
+
+    my $version
+      = run(qw{dpkg-query --showformat=${Version} --show}, $installable);
+
+    my $next_upstream_version = $version;
+    $next_upstream_version =~ s{ - [^-]* $}{}x;
+    $next_upstream_version .= $PLUS;
+
+    return
+      "$installable (>= $version), $installable (<< $next_upstream_version)";
+}
+
+=item ghc_pkg_field
+
+=cut
+
+sub ghc_pkg_field {
+    my ($compiler, $hackage_name, $field) = @_;
+
+    my $output
+      = run("$compiler-pkg", qw{--global field}, $hackage_name, $field);
+
+    # may not process multi-line fields correctly
+    my ($value) = split($NEWLINE, $output, 2);
+
+    return ($value // $EMPTY);
+}
+
+=item providing_package_for_ghc
+
+=cut
+
+sub providing_package_for_ghc {
+    my ($compiler, $package_id, $extension) = @_;
+
+    $extension //= $EMPTY;
+
+    my $ghc_version= run(qw{dpkg-query --showformat=${Version} --show ghc});
+
+    my $hackage_name;
+    if (
+        system(
+            qw{dpkg --compare-versions}, $ghc_version,
+            $DOUBLE_LESS_THAN, $MINIMUM_GHC_VERSION
+        ) == 0
+    ) {
+        $hackage_name = strip_hash($package_id);
+    } else {
+        $hackage_name = $package_id;
+    }
+
+    my $directory_line
+      = ghc_pkg_field($compiler, $hackage_name, 'library-dirs');
+    my (undef, $directory_list) = split(m{ \s* : \s* }x, $directory_line, 2);
+    my @library_dirs = split(m{ \s* , \s* }x, $directory_list);
+
+    my $library_line = ghc_pkg_field($compiler, $hackage_name, 'hs-libraries');
+    my (undef, $library_list) = split(m{ \s* : \s* }x, $library_line, 2);
+    my @libraries = split(m{ \s* , \s* }x, $library_list);
+
+    # look only at the first one
+    my $library = $libraries[0];
+
+    for my $directory (@library_dirs) {
+
+        my $library_path = "$directory/lib$library$extension.a";
+        next
+          unless -e $library_path;
+
+        my $line = run(qw{dpkg-query --search}, $library_path);
+        my ($installable) = split(m{ \s* : \s* }x, $line, 2);
+
+        return $installable;
+    }
+
+    return ();
+}
+
+=item providing_package_for_ghc_prof
+
+=cut
+
+sub providing_package_for_ghc_prof {
+    my ($compiler, $package_id) = @_;
+
+    return providing_package_for_ghc($compiler, $package_id, '_p');
+}
+
+=item cabal_pkg_ids
+
+=cut
+
+sub cabal_package_ids {
+    my (@configs) = @_;
+
+    my @ghc_pkg = tmp_package_db(@configs);
+
+    my @package_ids;
+    for my $config (@configs) {
+
+        my $name = path($config)->basename(qr{ [.]conf $}x);
+        push(@package_ids,
+            run(@ghc_pkg, qw{--simple-output field}, $name, 'id'));
+    }
+
+    return @package_ids;
+}
+
+=item cabal_depends
+
+=cut
+
+sub cabal_depends {
+    my (@configs) = @_;
+
+    # fix sort order
+    local $ENV{LC_ALL} = 'C';
+
+    my @ghc_pkg = tmp_package_db(@configs);
+
+    my @constraints;
+    for my $config (@configs) {
+
+        my $name = path($config)->basename(qr{ [.]conf $}x);
+        my $depends
+          = run(@ghc_pkg, qw{--simple-output field}, $name, 'depends');
+        push(@constraints, split($SPACE, $depends // $EMPTY));
+    }
+
+    my @have = sort +uniq @constraints;
+    my @exclude_patterns = split($SPACE, $ENV{DH_EXCLUDES} // $EMPTY);
+
+    # not sure this complies with Debhelper expectations
+    # excluded installables matching the patterns with or without version
+    # the versions should probably be dropped by the caller
+    s{ - [0-9] [.0-9a-zA-Z]* $}{}x for @exclude_patterns;
+
+    my @retained;
+    for my $constraint (@have) {
+
+        next
+          if any { $constraint =~ m{\Q$_\E} } @exclude_patterns;
+
+        push(@retained, $constraint);
+    }
+
+    return @retained;
+}
+
+=item hashed_dependency
+
+=cut
+
+sub hashed_dependency {
+    my ($compiler, $type, $package_id) = @_;
+
+    my @ghc_pkg = usable_ghc_pkg();
+    my $virtual_pkg
+      = package_id_to_virtual_package($compiler, $type, $package_id, @ghc_pkg);
+
+    # as a transition measure, check if dpkg knows about this virtual package
+    return $virtual_pkg
+      if system("dpkg-query --show $virtual_pkg > /dev/null 2> /dev/null")== 0;
+
+    return ();
+}
+
+=item composite_constraints
+
+=cut
+
+sub composite_constraints {
+    my ($compiler, $type, @configs) = @_;
+
+    my @package_ids = cabal_depends(@configs);
+
+    my @constraints;
+    for my $package_id (@package_ids) {
+
+        my $constraint = hashed_dependency($compiler, $type, $package_id);
+
+        if (!length $constraint) {
+
+            my $installable= providing_package_for_ghc($compiler, $package_id);
+
+            $constraint = dependency($installable);
+            if (!length $constraint) {
+
+                warn encode_utf8(
+"WARNING: No Debian package provides haskell package $package_id.\n"
+                );
+                next;
+            }
+        }
+
+        push(@constraints, $constraint);
+    }
+
+    return join($COMMA . $SPACE, @constraints);
+}
+
+=item depends_for_ghc_prof
+
+=cut
+
+sub depends_for_ghc {
+    my ($compiler, @configs) = @_;
+
+    return composite_constraints($compiler, 'dev', @configs);
+}
+
+=item depends_for_ghc_prof
+
+=cut
+
+sub depends_for_ghc_prof {
+    my ($compiler, @configs) = @_;
+
+    return composite_constraints($compiler, 'prof', @configs);
+}
+
+=item usable_ghc_pkg
+
+=cut
+
+sub usable_ghc_pkg {
+    my () = @_;
+
+    my @ghc_pkg;
+    my $version;
+
+    my $inplace_ghc_pkg = 'inplace/bin/ghc-pkg';
+    if (-x $inplace_ghc_pkg) {
+
+        # we are building ghc and need to use the new ghc-pkg
+        @ghc_pkg = ($inplace_ghc_pkg);
+        $version = run(qw{dpkg-parsechangelog --show-field Version});
+
+    } else {
+        @ghc_pkg = qw{ghc-pkg};
+        $version= run(qw{dpkg-query --showformat=${Version} --show ghc});
+    }
+
+    # ghc-pkg prior to version 8 is unusable for our purposes.
+    return ()
+      if system(qw{dpkg --compare-versions},
+        $version, $DOUBLE_LESS_THAN, $MINIMUM_GHC_VERSION)== 0;
+
+    return @ghc_pkg;
+}
+
+=item tmp_package_db
+
+=cut
+
+sub tmp_package_db {
+    my (@configs) = @_;
+
+    my @ghc_pkg = usable_ghc_pkg();
+    return ()
+      unless @ghc_pkg;
+
+    if (!-e 'debian/tmp-db/package.cache') {
+
+        run(qw{mkdir debian/tmp-db});
+        run(qw{cp}, @configs, 'debian/tmp-db/');
+
+        # Silence GHC 8.4's warning
+        # "ignoring (possibly broken) abi-depends field for packages"
+        # see also https://ghc.haskell.org/trac/ghc/ticket/14381
+        run(@ghc_pkg, qw{--package-db debian/tmp-db/ recache});
+    }
+
+    return (@ghc_pkg, qw{--package-db debian/tmp-db});
+}
+
+=item composite_provides
+
+=cut
+
+sub composite_provides {
+    my ($compiler, $type, @configs) = @_;
+
+    my @ghc_pkg = tmp_package_db(@configs);
+    my @package_ids = cabal_package_ids(@configs);
+
+    my @virtual;
+    push(@virtual,
+        package_id_to_virtual_package($compiler, $type, $_, @ghc_pkg))
+      for @package_ids;
+
+    return join($COMMA . $SPACE, @virtual);
+}
+
+=item provide_for_ghc
+
+=cut
+
+sub provides_for_ghc {
+    my ($compiler, @configs) = @_;
+
+    return composite_provides($compiler, 'dev', @configs);
+}
+
+=item provide_for_ghc_prof
+
+=cut
+
+sub provides_for_ghc_prof {
+    my ($compiler, @configs) = @_;
+
+    return composite_provides($compiler, 'prof', @configs);
+}
+
+=item package_id_to_virtual_package
+
+=cut
+
+sub package_id_to_virtual_package {
+    my ($compiler, $type, $package_id, @ghc_pkg) = @_;
+
+    my $name;
+    my $version;
+    my $long_abi;
+
+    if (@ghc_pkg) {
+
+        $name = run(@ghc_pkg, qw{--simple-output --unit-id field},
+            $package_id, 'name');
+        $version = run(@ghc_pkg, qw{--simple-output --unit-id field},
+            $package_id, 'version');
+        $long_abi = run(@ghc_pkg, qw{--simple-output --unit-id field},
+            $package_id, 'abi');
+
+    } else {
+
+        # no usable ghc-pkg; parse package id
+        my $lowercase = lc $package_id;
+
+        ($name, $version, $long_abi)
+          = ($lowercase =~ m{^ ([a-z0-9-]+) - ([0-9.]+) - (\S{32}) $}x);
+    }
+
+    # retain only the first five hex digits from abi out of 32
+    my ($short_abi) = ($long_abi =~ m{^ (\S{5}) }x);
+
+    my $virtual = lc "lib$compiler-$name-$type-$version-$short_abi";
+
+    return $virtual;
+}
+
+=item depends_for_hugs
+
+=cut
+
+sub depends_for_hugs {
+    my () = @_;
+
+    my $version= run(qw{dpkg-query --showformat=${Version} --show hugs});
+    my $upstream_version = $version;
+    $upstream_version =~ s{ - [^-]* $}{}x;
+
+    return "hugs (>= $upstream_version)";
+}
+
+=item find_config_for_ghc
+
+=cut
+
+sub find_config_for_ghc {
+    my ($installable) = @_;
+
+    my $pkgdir = package_pkgdir($installable);
+
+    if ($installable =~ s{ - prof $}{}x) {
+
+        $installable .= '-dev'
+          unless $installable eq 'ghc';
+    }
+
+    my @configs = grep { $_->is_file }
+      path("debian/$installable/$pkgdir")->children(qr{ [.]conf $}x);
+
+    return @configs;
+}
+
+=item clean_recipe
+
+=cut
+
+sub clean_recipe {
+    my () = @_;
+
+    run($ENV{DEB_SETUP_BIN_NAME}, qw{clean})
+      if -x $ENV{DEB_SETUP_BIN_NAME};
+
+    run(
+        qw{rm -rf dist dist-ghc dist-ghcjs dist-hugs},
+        $ENV{DEB_SETUP_BIN_NAME},
+        qw{Setup.hi Setup.ho Setup.o},
+        glob('.*config*'));
+    run(
+        qw{rm -f configure-ghc-stamp configure-ghcjs-stamp build-ghc-stamp build-ghcjs-stamp build-hugs-stamp build-haddock-stamp}
+    );
+    run(qw{rm -rf debian/tmp-inst-ghc debian/tmp-inst-ghcjs});
+    run(qw{rm -f debian/extra-depends-ghc debian/extra-depends-ghcjs});
+
+    if (-e $ENV{DEB_LINTIAN_OVERRIDES_FILE}) {
+        run(
+            qw{sed -i},
+            '/binary-or-shlib-defines-rpath/ d',
+            $ENV{DEB_LINTIAN_OVERRIDES_FILE});
+        run('find',$ENV{DEB_LINTIAN_OVERRIDES_FILE},qw{-empty -delete});
+    }
+
+    run(qw{rm -f}, $ENV{MAKEFILE});
+    run(qw{rm -rf debian/dh_haskell_shlibdeps});
+    run(qw{rm -rf debian/tmp-db});
+
+    return;
+}
+
+=item make_setup_recipe
+
+=cut
+
+sub make_setup_recipe {
+    my () = @_;
+
+    my $shipped_setup = first_value { -e } qw{Setup.lhs Setup.hs};
+
+    if (length $shipped_setup) {
+
+        run(qw{ghc --make}, $shipped_setup, '-o',$ENV{DEB_SETUP_BIN_NAME});
+        return;
+    }
+
+# Having a Setup.hs is considered good practice, but there are a few
+# Haskell packages that don't, since cabal does not use it for build types
+# other than 'Custom'. Find out the build type and use the corresponding
+# standardized Setup.hs file. For more information, see
+# https://www.haskell.org/cabal/users-guide/developing-packages.html#pkg-field-build-type
+
+    my $cabal_path = "$ENV{CABAL_PACKAGE}.cabal";
+    my $cabal_contents = path($cabal_path)->slurp_utf8;
+
+    my $cabal_version= first_value { length }
+    ($cabal_contents
+          =~ m{^ cabal-version: (?: \s+ [<>=]+ )? \s+ (\S+) \s* $}mix);
+    die encode_utf8("No cabal-version in $cabal_path")
+      unless length $cabal_version;
+
+    my $build_type= first_value { length }
+    ($cabal_contents =~ m{^ build-type: \s+ (\w+) \s* }mix);
+
+  # https://cabal.readthedocs.io/en/3.4/cabal-package.html#pkg-field-build-type
+    my $default_build_type = 'Simple';
+    $default_build_type = 'Custom'
+      if $cabal_version < $CABAL_VERSION_IMPLYING_SIMPLE_BUILDS
+      || $cabal_contents =~ m{^ custom-setup \s+ }mi;
+
+    $build_type //= $default_build_type;
+
+    my $stock_setup = "/usr/share/haskell-devscripts/Setup-$build_type.hs";
+    die encode_utf8("Could not find a suitable Setup.hs file for $build_type")
+      unless -e $stock_setup;
+
+    run(
+        qw{ghc --make}, $stock_setup, '-o',
+        $ENV{DEB_SETUP_BIN_NAME},
+        qw{-outputdir debian/tmp-setup-hs}
+    );
+
+    return;
+}
+
+=item configure_recipe
+
+=cut
+
+sub configure_recipe {
+    my () = @_;
+
+    # deleted when out of scope
+    my $time_reference = Path::Tiny->tempfile;
+    $time_reference->touch(str2time('1975-01-01', 'UTC'));
+
+    # dak does not like file timestamps older than 1975
+    # new tarballs from Hackage have files with mtimes at the
+    # beginning of the epoch, so set old mtimes to 1998
+    run(
+        qw{find . ! -newer},
+        $time_reference->stringify,
+        qw{-exec touch -d "1998-01-01 UTC" {} ; }
+    );
+
+    my $compiler = packages_hc();
+
+    my @installables = split($SPACE, $ENV{DEB_PACKAGES} // $EMPTY);
+    my @extensions = map { package_ext($_) } @installables;
+
+    my $profiling;
+    $profiling = '--enable-library-profiling'
+      if any { $_ eq 'prof' } @extensions;
+
+    my $ldflags_line = run(qw{dpkg-buildflags --get LDFLAGS});
+    my @ldflags = split($SPACE, $ldflags_line);
+    my @ghc_options = map { "--ghc-option=-optl$_" } @ldflags;
+
+    my $pkgdir = hc_pkgdir($compiler);
+    my $prefix = hc_prefix($compiler);
+    my $libdir = hc_libdir($compiler);
+    my $docdir
+      = hc_docdir($compiler, "$ENV{CABAL_PACKAGE}-$ENV{CABAL_VERSION}");
+    my $htmldir = hc_htmldir($compiler, $ENV{CABAL_PACKAGE});
+
+    # DEB_SETUP_GHC_CONFIGURE_ARGS can contain multiple arguments
+    # with their own quoting so run through shell a expansion
+    my $ghc_configure_args = run_quiet(qw{sh -c echo -n},
+        split($SPACE, $ENV{DEB_SETUP_GHC_CONFIGURE_ARGS} // $EMPTY));
+
+    # the versioned form DEB_SETUP_GHC6_CONFIGURE_ARGS should perhaps be
+    # abandoned in favor of the unversioned DEB_SETUP_GHC_CONFIGURE_ARGS
+
+    run(
+        $ENV{DEB_SETUP_BIN_NAME},
+        'configure',
+        "--$compiler",
+        '-v2',
+        "--package-db=/$pkgdir",
+        "--prefix=/$prefix",
+        "--libdir=/$libdir",
+        '--libexecdir=/usr/lib',
+        "--builddir=dist-$compiler",
+        @ghc_options,
+        "--haddockdir=/$docdir",
+        "--datasubdir=$ENV{CABAL_PACKAGE}",
+        "--htmldir=/$htmldir",
+        $profiling,
+        $ENV{NO_GHCI_FLAG},
+        split($SPACE, $ENV{DEB_SETUP_GHC6_CONFIGURE_ARGS} // $EMPTY),
+        split($SPACE, $ghc_configure_args // $EMPTY),
+        split($SPACE, $ENV{OPTIMIZATION} // $EMPTY),
+        split($SPACE, $ENV{TESTS} // $EMPTY));
+
+    return;
+}
+
+=item build_recipe
+
+=cut
+
+sub build_recipe {
+    my () = @_;
+
+    my $compiler = packages_hc();
+    my $output
+      = run($ENV{DEB_SETUP_BIN_NAME},'build', "--builddir=dist-$compiler");
+
+    return;
+}
+
+=item check_recipe
+
+=cut
+
+sub check_recipe {
+    my () = @_;
+
+    my $compiler = packages_hc();
+    my $output = run($ENV{DEB_SETUP_BIN_NAME},
+        'test', "--builddir=dist-$compiler", '--show-details=direct');
+
+    return;
+}
+
+=item haddock_recipe
+
+=cut
+
+sub haddock_recipe {
+    my () = @_;
+
+    my $compiler = packages_hc();
+    my $haddock = hc_haddock($compiler);
+
+    return
+      unless -x "/usr/bin/$haddock";
+
+    run(
+        $ENV{DEB_SETUP_BIN_NAME},
+        'haddock',
+        "--builddir=dist-$compiler",
+        "--with-haddock=/usr/bin/$haddock",
+        "--with-ghc=$compiler",
+        '--verbose=2',
+        split($SPACE, $ENV{DEB_HADDOCK_OPTS} // $EMPTY));
+
+    return;
+}
+
+=item extra_depends_recipe
+
+=cut
+
+sub extra_depends_recipe {
+    my ($compiler) = @_;
+
+    local $ENV{LC_ALL} = 'C.UTF-8';
+
+    my $output = run($ENV{DEB_SETUP_BIN_NAME},
+        'register', "--builddir=dist-$compiler",
+        qw{--gen-pkg-config --verbose=verbose+nowrap});
+
+    die encode_utf8('Cannot get name of package registration file.')
+      unless $output
+      =~ m{^Creating \s package \s registration \s file: \s+ (\S+) $}mx;
+
+    my $pkg_config = $1;
+
+    run('dh_haskell_extra_depends', $compiler, $pkg_config);
+    run(qw{rm -f}, $pkg_config);
+
+    return;
+}
+
+=item install_dev_recipe
+
+=cut
+
+sub install_dev_recipe {
+    my ($installable) = @_;
+
+    local $ENV{LC_ALL} = 'C.UTF-8';
+
+    my $compiler = package_hc($installable);
+    my $libdir = package_libdir($installable);
+    my $pkgdir = package_pkgdir($installable);
+
+    my $savedir = Cwd::getcwd;
+    chdir("debian/tmp-inst-$compiler")
+      or warn encode_utf8("Cannot change folder to debian/tmp-inst-$compiler");
+
+    run(qw{mkdir --parents}, $libdir);
+    run(
+        'find', $libdir,
+        qw{ ( ! -name *_p.a ! -name *.p_hi ! -type d ) },
+        qw{-exec install -Dm 644},
+        '{}', "../$installable/{}", $SEMICOLON
+    );
+
+    chdir($savedir)
+      or warn encode_utf8("Cannot change folder to $savedir");
+
+    my $output = run($ENV{DEB_SETUP_BIN_NAME},
+        'register', "--builddir=dist-$compiler",
+        qw{--gen-pkg-config --verbose=verbose+nowrap});
+
+    die encode_utf8('Cannot get name of package registration file.')
+      unless $output
+      =~ m{^Creating \s package \s registration \s file: \s+ (\S+) $}mx;
+
+    my $pkg_config = $1;
+
+    run(qw{sed -i}, 's/^exposed: True$/exposed: False/', $pkg_config)
+      if length $ENV{HASKELL_HIDE_PACKAGES};
+
+    run(qw{install -Dm 644},
+        $pkg_config, "debian/$installable/$pkgdir/$pkg_config");
+    run(qw{rm -f}, $pkg_config);
+
+    if (length $ENV{DEB_GHC_EXTRA_PACKAGES}) {
+
+        my $EP_DIR
+          = "debian/$installable/usr/lib/haskell-packages/extra-packages";
+        run(qw{mkdir --parents}, $EP_DIR);
+
+        path("$EP_DIR/$ENV{CABAL_PACKAGE}-$ENV{CABAL_VERSION}")
+          ->spew_utf8($ENV{DEB_GHC_EXTRA_PACKAGES});
+    }
+
+    path($ENV{DEB_LINTIAN_OVERRIDES_FILE})
+      ->append_utf8('binary-or-shlib-defines-rpath' . $NEWLINE)
+      unless -e $ENV{DEB_LINTIAN_OVERRIDES_FILE}
+      && path($ENV{DEB_LINTIAN_OVERRIDES_FILE})->slurp_utf8
+      =~ m{^ binary-or-shlib-defines-rpath }x;
+
+    run('dh_haskell_provides', "--package=$installable");
+    run('dh_haskell_depends', "--package=$installable");
+    run('dh_haskell_shlibdeps', "--package=$installable");
+
+    return;
+}
+
+=item install_prof_recipe
+
+=cut
+
+sub install_prof_recipe {
+    my ($installable) = @_;
+
+    my $compiler = package_hc($installable);
+    my $libdir = package_libdir($installable);
+
+    my $savedir = Cwd::getcwd;
+    chdir("debian/tmp-inst-$compiler")
+      or warn encode_utf8("Cannot change folder to debian/tmp-inst-$compiler");
+
+    run(qw{mkdir --parents}, $libdir);
+    run(
+        'find', $libdir,
+        qw{ ( -name *_p.a -o -name *.p_hi ) },
+        qw{-exec install -Dm 644},
+        '{}', "../$installable/{}", $SEMICOLON
+    );
+
+    chdir($savedir)
+      or warn encode_utf8("Cannot change folder to $savedir");
+
+    run('dh_haskell_provides', "--package=$installable");
+    run('dh_haskell_depends', "--package=$installable");
+
+    return;
+}
+
+=item install_doc_recipe
+
+=cut
+
+sub install_doc_recipe {
+    my ($installable) = @_;
+
+    my $compiler = package_hc($installable);
+
+    my $htmldir = hc_htmldir($compiler, $ENV{CABAL_PACKAGE});
+    run(qw{mkdir --parents}, "debian/$installable/$htmldir");
+
+    my $savedir = Cwd::getcwd;
+    chdir("debian/tmp-inst-$compiler")
+      or warn encode_utf8("Cannot change folder to debian/tmp-inst-$compiler");
+
+    run(
+        'find', "./$htmldir",
+        qw{ ! -name *.haddock ! -type d},
+        qw{-exec install -Dm 644},
+        '{}', "../$installable/{}", $SEMICOLON
+    );
+
+    chdir($savedir)
+      or warn encode_utf8("Cannot change folder to $savedir");
+
+    my $docdir
+      = hc_docdir($compiler, "$ENV{CABAL_PACKAGE}-$ENV{CABAL_VERSION}");
+
+    my $tmp_inst_docdir = "debian/tmp-inst-$compiler/$docdir";
+    my $installable_docdir = "debian/$installable/$docdir";
+
+    run(qw{mkdir --parents}, $installable_docdir);
+
+    run(qw{cp --recursive}, $_->stringify, $installable_docdir)
+      for path($tmp_inst_docdir)->children(qr{ [.]haddock $}x);
+
+    if ($ENV{DEB_ENABLE_HOOGLE} eq 'yes') {
+
+        # We cannot just invoke dh_link here because that acts on
+        # either libghc-*-dev or all the binary packages, neither of
+        # which is desirable (see dh_link (1)).  So we just create a
+        # (policy-compliant) symlink ourselves
+
+        my $target = "debian/$installable/$htmldir/$ENV{CABAL_PACKAGE}.txt";
+        if (-e $target) {
+
+            my $hoogle = hc_hoogle($compiler);
+            my $name = "debian/$installable$hoogle$installable.txt";
+
+            run(qw{mkdir --parents}, dirname($name));
+            run(qw{ln --symbolic --relative --no-target-directory},
+                $target, $name);
+        }
+    }
+
+    run('dh_haskell_depends', "--package=$installable");
+
+    return;
+}
+
+=head1 AUTHOR
+
+Written by Felix Lechner <felix.lechner at lease-up.com> for Haskell Devscripts.
+Based on Dh_Haskell.sh.
+
+=head1 SEE ALSO
+
+Debian::Debhelper::Buildsystem::haskell(3pm)
+
+=cut
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et



View it on GitLab: https://salsa.debian.org/haskell-team/haskell-devscripts/-/compare/2bb0ad436d03b33ca148149c999ed86193ec9a2e...8d20067a2a3ce3a6c40775e36f8d265520b70922

-- 
View it on GitLab: https://salsa.debian.org/haskell-team/haskell-devscripts/-/compare/2bb0ad436d03b33ca148149c999ed86193ec9a2e...8d20067a2a3ce3a6c40775e36f8d265520b70922
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-haskell-commits/attachments/20220403/7e6ffd27/attachment-0001.htm>


More information about the Pkg-haskell-commits mailing list