diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
-* 0.13.3 (2019-05-10)
-- default to lts-12
+# 1.0.1 (2019-09-29)
+- doc and prof subpackages for libraries
+- reworked to use optparse-applicative (simple-cmd-args)
+- default to Stackage LTS 13
+- F31+ uses triggers for ghc-pkg recache
+- wait 10^4s (< 3 hours) between cabal update's
+- refactor for simple-cabal 1.0, PackageName and LibPkgType
+- handle setup-depends
+- diff: autodetect subpackaging
+- diff (experimental): trim %changelog with bawolk/hsp if available
+- drop pre-built manpage: use Makefile to build it
+
+# 0.13.3 (2019-05-10)
+- default stream to lts-12
 - repoquery for missing deps' package .conf file to avoid modular ghc conflicts
 - only --assumeyes for dnf install when not tty
 - give up if more than one spec file
@@ -9,14 +21,14 @@
 - finalPackageDescription for debugging Cabal
 - use simple-cmd-0.1.3.1 for sudo fixes
 
-* 0.13.2 (2019-04-09)
+# 0.13.2 (2019-04-09)
 - include ANNOUNCE in docs
 - if dependency parallel directory exists, don't check if installed
 - fix buildDepends on Cabal-2.4
 - new --standalone option for private packages built with cabal-install
 - print --{missing,standalone,subpackage} options on spec file header line
 
-* 0.13.1 (2019-02-27)
+# 0.13.1 (2019-02-27)
 - update: fix rw git dir detection
 - fix tarball downloading and copying of revised .cabal file
 - show output (errors) when prepping source and prep in working dir
@@ -24,7 +36,7 @@
 - need chrpath for subpackages
 - move license dir to any common subpackage
 
-* 0.13 (2019-02-18)
+# 0.13 (2019-02-18)
 - improve license and doc filtering
 - backup revised .cabal files
 - fallback to spectool for source downloading
@@ -34,7 +46,7 @@
 - only run "cabal update" if more than 10min old
 - drop support for ghc-7.4.2
 
-* 0.12.6 (2018-10-20)
+# 0.12.6 (2018-10-20)
 - update: remove old revised .cabal
 - convert revised .cabal file to unix format
 - spec: support haskell-gi libraries
@@ -45,7 +57,7 @@
 - support ghc_without_dynamic for static executables
 - build with Cabal-2.4 (ghc-8.6)
 
-* 0.12.5 (2018-07-29)
+# 0.12.5 (2018-07-29)
 - update: more careful now with fuzz 1
 -- handle revised to non-revised
 -- improved for subpackaging
@@ -57,21 +69,21 @@
 - missing: better output for missing sub-deps
 - do not put doc* in docs
 
-* 0.12.4 (2018-05-31)
+# 0.12.4 (2018-05-31)
 - now uses Hackage revisions of packages (using wget)
 - spec --stream STREAM replaces --hackage
 - disable https for ghc < 7.10
 
-* 0.12.3 (2018-05-14)
+# 0.12.3 (2018-05-14)
 - build: remove erroneous tarball check
 - refresh: use cblrpm for old cabal-rpm
 
-* 0.12.2 (2018-03-29)
+# 0.12.2 (2018-03-29)
 - diff now supports CBLRPM_DIFF envvar to override "diff -u"
 - try to build even when missing rpms deps not available
 - package now builds with Cabal-2.2
 
-* 0.12.1 (2018-02-20)
+# 0.12.1 (2018-02-20)
 - new option --missing: comments out missing dependencies
 - put license files in lib subpackage
 - no longer append %_isa to C BuildRequires (#54)
@@ -79,7 +91,7 @@
 - change 'cblrpm' to 'cabal-rpm' in documentation
 - drop support for SCM snapshot releases
 
-* 0.12 (2017-11-17)
+# 0.12 (2017-11-17)
 - default to querying stackage.org directly via https
 - fix stackage-query usage and suggest installing if missing
 - run cabal update before cabal commands
@@ -89,13 +101,13 @@
 - silence mock rpmbuild -bs warnings about undefined %ghc_version
 - allow building with ghc-8.2 and Cabal-2.0
 
-* 0.11.2 (2017-07-31)
+# 0.11.2 (2017-07-31)
 - fix cabal-rpm update --subpackage
 - fix rpm installation when no sudo (#49)
 - fix handling of no exposed modules (#50)
 - fix license handling for selfdep binlib (#51)
 
-* 0.11.1 (2017-03-13)
+# 0.11.1 (2017-03-13)
 - support building meta (compat) packages
 - invocation of optional stackage-query to update to LTS now works
 - initial --subpackage support for %{subpkgs} of missing deps:
@@ -104,7 +116,7 @@
 - (+-+) absorbs extra space
 - update no longer resets release for %{subpkgs}
 
-* 0.11 (2017-01-27)
+# 0.11 (2017-01-27)
 - refresh command now reads the cabal-rpm version header in the spec file and
   installs that version of cabal-rpm under ~/.cblrpm/ and uses it to make patch
 - diff and update now follow package-version args
@@ -115,13 +127,13 @@
 - rename Setup to Options
 - silence <$> import warnings
 
-* 0.10.1 (2016-11-29)
+# 0.10.1 (2016-11-29)
 - no longer need to remove License file by hand
 - use new %ghc_fix_rpath
 - include Contributors in docs
 - warn about duplicate docs in datadir and remove them
 
-* 0.10.0 (2016-07-27)
+# 0.10.0 (2016-07-27)
 - rename executable and manpage back to 'cabal-rpm': more predictable
 - explicit error for unknown command
 - sort docs and include upstream changelogs and news
@@ -140,50 +152,50 @@
 - package datadir better
 - for SUSE libs executables now go in the base package
 
-* 0.9.11 (2016-05-06)
+# 0.9.11 (2016-05-06)
 - build with Cabal-1.24
 
-* 0.9.10 (2016-03-24)
+# 0.9.10 (2016-03-24)
 - bugfixes
   - update no longer tries to grep non-existent .git
   - fix duplicate clibs
 - fix build with ghc-8.0 (Cabal-1.23 and time-1.6)
 - SuSE improvements: no disttag or rpmdev-bumpspec
 
-* 0.9.9 (2016-01-25)
+# 0.9.9 (2016-01-25)
 - couple of minor improvements for SUSE packaging
 
-* 0.9.8 (2015-10-08)
+# 0.9.8 (2015-10-08)
 - better %license logic
 - fix handling of versions without '.'
 - no duplicate test deps
 
-* 0.9.7 (2015-08-28)
+# 0.9.7 (2015-08-28)
 - only list buildable executables in spec file
 - bring back 'build' as an alias for 'local'
 - use %license macro
 - do not warn about missing optional system programs
 
-* 0.9.6 (2015-05-21)
+# 0.9.6 (2015-05-21)
 - make "cabal list" quiet
 - filter missing packages from repoquery
 
-* 0.9.5.1 (2015-05-01)
+# 0.9.5.1 (2015-05-01)
 - add old-locale Cabal flag to fix build on ghc-7.10
 
-* 0.9.5 (2015-04-20)
+# 0.9.5 (2015-04-20)
 - fix for dnf repoquery
 - create SOURCES/ for tarball
 - fixes for Cabal-1.22
 - nogpgcheck for Fedora 22+
 - warn about hidden backup spec files
 
-* 0.9.4 (2015-02-17)
+# 0.9.4 (2015-02-17)
 - use dnf if installed instead of yum for install and repoquery
 - update now only commits changes and new source if git origin is ssh
 - allow Cabal-1.22
 
-* 0.9.3 (2015-02-05)
+# 0.9.3 (2015-02-05)
 - make sure tarball destdir exists before copying
 - improve output for listing missing packages
 - update improvements: new-sources first, continue if patch fails, git commit changes
@@ -191,7 +203,7 @@
 - drop the debuginfo handling for C files
 - ignore emacs temp ".#pkgname.spec" files
 
-* 0.9.2 (2014-12-18)
+# 0.9.2 (2014-12-18)
 - lots of bug fixes
 - improved missingdeps output
 - use https for hackage URLs (codeblock)
@@ -201,14 +213,14 @@
 - fix build and warnings for Cabal 1.20
 - use TMPDIR
 
-* 0.9.1 (2014-08-26)
+# 0.9.1 (2014-08-26)
 - missingdeps now lists missing dependencies recursively and outputs Hackage
   package names rather than ghc-*-devel package names
 - do not assume package order when testing if dependencies installed
 - check  ~/.cabal/packages/ exists before looking for tarballs
 - pass actual exeNames to %ghc_fix_dynamic_rpath
 
-* 0.9 (2014-07-17)
+# 0.9 (2014-07-17)
 - reworked initial logic to make better use of existing spec files,
   and prep source tree properly
 - default to Library packaging instead of BinLib:
@@ -224,7 +236,7 @@
 - include "cblrpm" in tempdir names
 - use current dir name as a last guess of package name
 
-* 0.8.11 (2014-05-17)
+# 0.8.11 (2014-05-17)
 - build command renamed again from "rpm" to "local" (like fedpkg)
 - use .spec file to determine pkg-ver when no .cabal file around
 - automatically generate bcond for %check and add testsuite BRs
@@ -238,16 +250,16 @@
 - no longer depends on regex-compat
 - some refactorings
 
-* 0.8.10 (2014-03-03)
+# 0.8.10 (2014-03-03)
 - diff command replaces cblrpm-diff script
 - new missingdeps command
 - replace use of rpmspec: no "rpmspec --srpm" on RHEL 5 and 6
 
-* 0.8.9 (2014-02-10)
+# 0.8.9 (2014-02-10)
 - bugfix for error handling dir with spec file
 - cblrpm-diff arg is now optional
 
-* 0.8.8 (2014-02-09)
+# 0.8.8 (2014-02-09)
 - updated GPLv3 license headers
 - use .spec file to determine package if no .cabal file (works with
   or without arg)
@@ -261,7 +273,7 @@
 - new builddep command (like yum-buildep, but allows missing packages)
 - notice for overwriting existing spec file with force option
 
-* 0.8.7 (2013-12-31)
+# 0.8.7 (2013-12-31)
 - new "install" command wrapping "cabal install"
 - "build" command renamed to "rpm"
 - sort devel Requires
@@ -270,14 +282,14 @@
 - hlint cleanup
 - support AGPL license in Cabal-1.18
 
-* 0.8.6 (2013-10-04)
+# 0.8.6 (2013-10-04)
 - check for _darcs or .git dir in package topdir not pwd
 
-* 0.8.5 (2013-09-29)
+# 0.8.5 (2013-09-29)
 - fix repoquery when a package update exists for C lib
 - make cblrpm-diff quieter
 
-* 0.8.4 (2013-09-28)
+# 0.8.4 (2013-09-28)
 - use repoquery to determine extra C library dependencies
 - quote "pkgconfig(foo)" for rpm query and yum install
 - show sudo command before sudo password prompt appears
@@ -286,7 +298,7 @@
 - drop release from initial changelog entry for packager to add an entry
 - do not try to fetch tarball for a darcs or git source dir
 
-* 0.8.3 (2013-07-12)
+# 0.8.3 (2013-07-12)
 - only try to install missing dependencies
 - for executables depending on own lib add BR chrpath and %ghc_fix_dynamic_rpath
 - word-wrap generic descriptions
@@ -294,7 +306,7 @@
 - move modules to toplevel
 - Rpm module split into Spec and Build in Commands/
 
-* 0.8.2 (2013-07-02)
+# 0.8.2 (2013-07-02)
 - handle pkg-ver arg, and check cabal list is non-empty
 - sort all generated deps
 - use yum-builddep again to install deps
@@ -305,12 +317,12 @@
 - --version now outputs to stdout
 - new --force flag to overwrite existing .spec file
 
-* 0.8.1 (2013-06-14)
+# 0.8.1 (2013-06-14)
 - word wrapping of descriptions
 - use generic description for shared subpackage
 - simplify logic for summary and description processing
 
-* 0.8.0 (2013-05-31)
+# 0.8.0 (2013-05-31)
 - new simplier revision to Fedora Packaging
   - drop %common_summary and %common_description
   - drop %ghc_package, %ghc_description, %ghc_devel_package,
@@ -319,7 +331,7 @@
 - check external programs available before use
 - tweaks for ghc-7.6.3 and Cabal-1.16
 
-* 0.7.1 (2013-03-22)
+# 0.7.1 (2013-03-22)
 - add final full-stop to description if missing
 - add ver-rel to initial changelog entry
 - fix use of cblrpm-diff force lib option
@@ -328,7 +340,7 @@
 - output when trying a path
 - map curl C dep to libcurl
 
-* 0.7.0 (2013-01-22)
+# 0.7.0 (2013-01-22)
 - cabal-rpm command renamed to cblrpm, and cabal-rpm-diff to cblrpm-diff
 - cblrpm now has commands for spec, srpm, and build
 - cblrpm will try to install packaged uninstalled depends with sudo yum install
@@ -338,7 +350,7 @@
 - sort extralibs depends
 - cleanup of unused options and help output
 
-* 0.6.6 (2012-11-21)
+# 0.6.6 (2012-11-21)
 - generate BRs and Req's for C libraries (extra-libraries)
 - initial map for some C libs: libglut, libiw, libz, libX*
 - generate BRs and Req's for pkgconfig-depends
@@ -348,32 +360,32 @@
 - backup suffix changed from .cabal-rpm to .cblrpm
 - don't mistake non-existent file in cwd for a package
 
-* 0.6.5 (2012-11-01)
+# 0.6.5 (2012-11-01)
 - drop hscolour BuildRequires
 - simplify generated BuildRequires: drop version ranges for now,
   exclude pkg self, base libs, and Cabal
 - use ExclusiveArch ghc_arches_with_ghci for template-haskell dep
 - replace --name option with --library to force Lib
 
-* 0.6.4 (2012-09-25)
+# 0.6.4 (2012-09-25)
 - add cabal-rpm-diff
 - fix manpage generation
 
-* 0.6.3 (2012-09-24)
+# 0.6.3 (2012-09-24)
 - support tarball path argument
 - use a temporary working dir for opening tarball or cabal unpack
 - add a manpage
 
-* 0.6.2 (2012-09-10)
+# 0.6.2 (2012-09-10)
 - fix output of L/GPL version
 
-* 0.6.1 (2012-07-25)
+# 0.6.1 (2012-07-25)
 bugfixes:
 - fix "cabal-rpm pkg" when other *pkg* packages exist in hackage
 - always generate the extra docs list from the pkg src dir!
 - now no backslash at end of common_description
 
-* 0.6.0 (2012-07-24)
+# 0.6.0 (2012-07-24)
 - updated to work with Cabal >= 1.10 and current cabal2spec style packaging
   using currently actively used ghc-rpm-macros
 - should generate haskell dependencies correctly and also summary and
@@ -381,7 +393,7 @@
 - some of the generic compiler supported was dropped for simplicity
 - rpmbuild support will be re-introduced in a future version
 
-* 0.5.1 and earlier (2007-2008) released by Bryan O'Sullivan
+# 0.5.1 and earlier (2007-2008) released by Bryan O'Sullivan
 - should work with ghc-6.8
 
 
diff --git a/Makefile b/Makefile
new file mode 100644
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,4 @@
+man: man/cabal-rpm.1
+
+man/cabal-rpm.1: man/cabal-rpm.1.md
+	pandoc -s -t man $< > $@
diff --git a/TODO b/TODO
--- a/TODO
+++ b/TODO
@@ -1,3 +1,17 @@
+- switch to Cabal 2 for better License handling
+- builddep should only install ghc-*-devel not ghc-*-prof
+- type for rpm (dep) packages
+
+- spec --bounds
+- distinguish binlib executable and library build-deps
+  and library and testsuite build-tools
+- rework "BR: ghc-*-static" with %{?_isa}
+- jump from lts-N to lts-N+1 instead of straight to Hackage
+- move Main to app?
+- check for cabal executable
+- revisions of subpackages
+- use Set for deps?
+
 ## Misc
 ? run "cabal update" if package-version not found
 - read options from header line
@@ -17,8 +31,6 @@
 
 ## spec/packaging
 - filter or blockformat literate code in description ("> ...")
-- sort devel packages ignoring -devel suffix?
-? include version ranges in BRs
 ? use repoquery for missing testdeps
 - support tarballs again
 * filter dummy pkgs like fail, bytestring-builder and mtl-compat
@@ -43,7 +55,7 @@
 - use rpmspec + dnf/yum-builddep if needed to install deps not in .cabal
 
 ## install
-- check ghc version compatible
+- check ghc version compatible (done?)
 
 ## update
 - warm about new missing deps
diff --git a/cabal-rpm.cabal b/cabal-rpm.cabal
--- a/cabal-rpm.cabal
+++ b/cabal-rpm.cabal
@@ -1,5 +1,5 @@
 Name:                cabal-rpm
-Version:             0.13.3
+Version:             1.0.1
 Synopsis:            RPM packaging tool for Haskell Cabal-based packages
 Description:
     This package provides a RPM packaging tool for Haskell Cabal-based packages.
@@ -22,11 +22,11 @@
                      2012-2019 Jens Petersen <petersen@fedoraproject.org>
 Category:            Distribution
 Build-type:          Simple
-Extra-source-files:  README.md ChangeLog TODO man/cabal-rpm.1.md man/cabal-rpm.1
+Extra-source-files:  ChangeLog Makefile README.md TODO man/cabal-rpm.1.md
 Cabal-version:       >=1.6
 Tested-with:         GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3,
                      GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4,
-                     GHC == 8.6.3
+                     GHC == 8.6.5
 
 source-repository head
   type:     git
@@ -47,13 +47,17 @@
                    directory,
                    filepath,
                    process,
-                   simple-cmd >= 0.1.3.1,
+                   simple-cabal >= 0.1.0,
+                   simple-cmd >= 0.2.0,
+                   simple-cmd-args >= 0.1.2,
                    unix
     if flag(old-locale)
        Build-Depends: old-locale >= 1 && < 1.1,
                       time >= 1.2 && < 1.5
     else
        Build-Depends: time >= 1.5 && < 1.9
+    if impl(ghc<8.0)
+       Build-Depends: semigroups
     if impl(ghc >= 8.0) && flag(https)
        Build-Depends: bytestring,
                       http-client >= 0.4.30,
@@ -61,21 +65,21 @@
                       http-conduit
        Cpp-options: -DHTTPS
     Other-modules:
-        Commands.Depends,
-        Commands.Diff,
-        Commands.Install,
-        Commands.RpmBuild,
-        Commands.Refresh,
-        Commands.Spec,
-        Commands.Update,
-        Dependencies,
-        Distro,
-        FileUtils,
-        Options,
-        PackageUtils,
-        Stackage,
-        SysCmd,
-        Paths_cabal_rpm
+                  Commands.BuildDep,
+                  Commands.Depends,
+                  Commands.Diff,
+                  Commands.Install,
+                  Commands.RpmBuild,
+                  Commands.Refresh,
+                  Commands.Spec,
+                  Commands.Update,
+                  Dependencies,
+                  FileUtils,
+                  PackageUtils,
+                  Stackage,
+                  SysCmd,
+                  Types,
+                  Paths_cabal_rpm
     Hs-Source-Dirs:     src
     GHC-options:        -fwarn-missing-signatures -Wall
     Extensions:         CPP
diff --git a/man/cabal-rpm.1 b/man/cabal-rpm.1
deleted file mode 100644
--- a/man/cabal-rpm.1
+++ /dev/null
diff --git a/man/cabal-rpm.1.md b/man/cabal-rpm.1.md
--- a/man/cabal-rpm.1.md
+++ b/man/cabal-rpm.1.md
@@ -6,17 +6,17 @@
 cabal-rpm - a RPM packaging tool for Haskell Cabal packages
 
 # SYNOPSIS
-cabal-rpm [*options*] spec [*path-or-pkg*]
-cabal-rpm [*options*] local [*path-or-pkg*]
-cabal-rpm [*options*] srpm [*path-or-pkg*]
-cabal-rpm [*options*] prep [*path-or-pkg*]
-cabal-rpm [*options*] builddep [*path-or-pkg*]
-cabal-rpm [*options*] install [*path-or-pkg*]
-cabal-rpm [*options*] depends [*path-or-pkg*]
-cabal-rpm [*options*] requires [*path-or-pkg*]
-cabal-rpm [*options*] missingdeps [*path-or-pkg*]
-cabal-rpm [*options*] diff [*path-or-pkg*]
-cabal-rpm [*options*] update [*path-or-pkg*]
+cabal-rpm [*options*] spec [*path-or-pkg*]\
+cabal-rpm [*options*] local [*path-or-pkg*]\
+cabal-rpm [*options*] srpm [*path-or-pkg*]\
+cabal-rpm [*options*] prep [*path-or-pkg*]\
+cabal-rpm [*options*] builddep [*path-or-pkg*]\
+cabal-rpm [*options*] install [*path-or-pkg*]\
+cabal-rpm [*options*] depends [*path-or-pkg*]\
+cabal-rpm [*options*] requires [*path-or-pkg*]\
+cabal-rpm [*options*] missingdeps [*path-or-pkg*]\
+cabal-rpm [*options*] diff [*path-or-pkg*]\
+cabal-rpm [*options*] update [*path-or-pkg*\]\
 cabal-rpm [*options*] refresh [*path-or-pkg*]
 
 # DESCRIPTION
diff --git a/src/Commands/BuildDep.hs b/src/Commands/BuildDep.hs
new file mode 100644
--- /dev/null
+++ b/src/Commands/BuildDep.hs
@@ -0,0 +1,9 @@
+module Commands.BuildDep (builddep) where
+
+import Dependencies (pkgInstallMissing)
+import Types
+
+builddep :: Flags -> Stream -> Maybe Package -> IO ()
+builddep flags stream mpkg = do
+  missing <- pkgInstallMissing flags stream mpkg
+  mapM_ (builddep flags stream . Just) missing
diff --git a/src/Commands/Depends.hs b/src/Commands/Depends.hs
--- a/src/Commands/Depends.hs
+++ b/src/Commands/Depends.hs
@@ -17,9 +17,12 @@
     Depends (..)
     ) where
 
-import Dependencies (dependencies, missingPackages, packageDependencies)
-import Options (quiet)
-import PackageUtils (PackageData (..), prepare, repoquery, stripPkgDevel)
+import Dependencies (dependencies, ghcDep, LibPkgType(..), missingPackages,
+                     packageDependencies)
+import PackageUtils (PackageData (..), prepare, repoquery,
+                     stripPkgDevel, unPackageName)
+import Types
+
 import SimpleCmd ((+-+))
 
 #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
@@ -32,43 +35,44 @@
 
 data Depends = Depends | Requires | Missing
 
-depends :: PackageData -> Depends -> IO ()
-depends pkgdata action = do
+depends :: Depends -> Flags -> Stream -> Maybe Package -> IO ()
+depends action flags stream mpkg = do
+  pkgdata <- prepare flags stream mpkg False
   let pkgDesc = packageDesc pkgdata
   case action of
     Depends -> do
-      (deps, tools, clibs, pkgcfgs) <- dependencies pkgDesc
-      let clibs' = map (\ lib -> "lib" ++ lib <.> "so") clibs
-      let pkgcfgs' = map (<.> "pc") pkgcfgs
-      mapM_ putStrLn $ deps ++ tools ++ clibs' ++ pkgcfgs'
+      let (deps, setup, tools, clibs, pkgcfgs) = dependencies pkgDesc
+          clibs' = map (\ lib -> "lib" ++ lib <.> "so") clibs
+          pkgcfgs' = map (<.> "pc") pkgcfgs
+      mapM_ putStrLn $ map unPackageName (nub (deps ++ setup)) ++ tools ++ clibs' ++ pkgcfgs'
     Requires -> do
-      (deps, tools, clibs, pkgcfgs) <- packageDependencies False pkgDesc
-      mapM_ putStrLn $ sort $ deps ++ tools ++ clibs ++ pkgcfgs
+      (deps, setup, tools, clibs, pkgcfgs) <- packageDependencies pkgDesc
+      mapM_ putStrLn $ sort . nub  $ map (ghcDep LibDevel) (deps ++ setup) ++ tools ++ clibs ++ pkgcfgs
     Missing -> do
       miss <- missingPackages pkgDesc >>= filterM notAvail
       let missing = map stripPkgDevel miss
       mapM_ putStrLn missing
       unless (null missing) $
         putStrLn ""
-      void $ recurseMissing miss missing
+      void $ recurseMissing flags stream miss missing
 
-recurseMissing :: [String] -> [String] -> IO [String]
-recurseMissing already [] = return already
-recurseMissing already (dep:deps) = do
-  miss <- missingDepsPkg dep
+recurseMissing :: Flags -> Stream -> [String] -> [String] -> IO [String]
+recurseMissing _ _ already [] = return already
+recurseMissing flags stream already (dep:deps) = do
+  miss <- missingDepsPkg flags stream dep
   putMissing miss already
   let accum = nub $ miss ++ already
-  deeper <- recurseMissing accum (miss \\ accum)
+  deeper <- recurseMissing flags stream accum (miss \\ accum)
   let accum2 = nub $ accum ++ deeper
-  more <- recurseMissing accum2 (deps \\ accum2)
+  more <- recurseMissing flags stream accum2 (deps \\ accum2)
   return $ nub $ accum2 ++ more
 
 notAvail :: String -> IO Bool
 notAvail pkg = null <$> repoquery [] pkg
 
-missingDepsPkg :: String -> IO [String]
-missingDepsPkg pkg = do
-  pkgdata <- prepare quiet (Just pkg) False
+missingDepsPkg :: Flags -> Stream -> Package -> IO [String]
+missingDepsPkg flags stream pkg = do
+  pkgdata <- prepare flags stream (Just pkg) False
   missingPackages (packageDesc pkgdata) >>= filterM notAvail
 
 putMissing :: [String] -> [String] -> IO ()
diff --git a/src/Commands/Diff.hs b/src/Commands/Diff.hs
--- a/src/Commands/Diff.hs
+++ b/src/Commands/Diff.hs
@@ -18,27 +18,35 @@
   ) where
 
 import Commands.Spec (createSpecFile)
-import FileUtils (mktempdir, withCurrentDirectory)
-import Options (RpmFlags (..))
+import FileUtils (mktempdir)
 import PackageUtils (PackageData (..), prepare)
-import SimpleCmd ((+-+), shell_)
-import SysCmd (die)
+import SysCmd (die, optionalProgram)
+import Types
 
-import Data.Maybe (isNothing)
+import SimpleCmd (grep_, pipe_, pipe3_)
 
+import Distribution.Verbosity (silent)
 import System.Directory (removeDirectoryRecursive)
 import System.FilePath ((<.>))
 import System.Posix.Env (getEnvDefault)
 
-diff :: PackageData -> RpmFlags -> Maybe String -> IO ()
-diff pkgdata flags mpkg =
+diff :: Flags -> PackageType -> Stream -> Maybe Package -> IO ()
+diff flags pkgtype stream mpkg = do
+  pkgdata <- prepare flags stream mpkg True
   case specFilename pkgdata of
     Nothing -> die "No (unique) .spec file in directory."
     Just spec -> do
+      subpkg <- grep_ "%{subpkgs}" spec
       tmpdir <- mktempdir
-      pd <- if isNothing mpkg then return pkgdata
-            else withCurrentDirectory tmpdir $ prepare flags mpkg False
-      speccblrpm <- createSpecFile pd flags (Just tmpdir)
-      diffcmd <- getEnvDefault "CBLRPM_DIFF" "diff -u"
-      shell_ $ diffcmd +-+ spec +-+ speccblrpm +-+ "| sed -e s%" ++ speccblrpm ++ "%" ++ spec <.> "cblrpm" ++ "%"
+      speccblrpm <- createSpecFile silent flags False pkgtype subpkg stream (Just tmpdir) mpkg
+      diffcmd <- words <$> getEnvDefault "CBLRPM_DIFF" "diff -u"
+      hsp <- optionalProgram "hsp"
+      if hsp
+        then
+        pipe3_ (head diffcmd, tail diffcmd ++ [spec, speccblrpm])
+          ("sed", ["-e", "s%" ++ speccblrpm ++ "%" ++ spec <.> "cblrpm" ++ "%"])
+          ("hsp", ["takeWhile (not . (\"%changelog\" `T.isSuffixOf`) . getText) pp | p"])
+        else
+        pipe_ (head diffcmd, tail diffcmd ++ [spec, speccblrpm])
+        ("sed", ["-e", "s%" ++ speccblrpm ++ "%" ++ spec <.> "cblrpm" ++ "%"])
       removeDirectoryRecursive tmpdir
diff --git a/src/Commands/Install.hs b/src/Commands/Install.hs
--- a/src/Commands/Install.hs
+++ b/src/Commands/Install.hs
@@ -18,34 +18,32 @@
     ) where
 
 import Commands.RpmBuild (rpmBuild)
-import Dependencies (missingPackages, notInstalled, pkgInstallMissing)
+import Dependencies (notInstalled, pkgInstallMissing)
 import FileUtils (withTempDirectory)
-import Options (RpmFlags (..))
-import PackageUtils (PackageData (..), rpmInstall, RpmStage (..), stripPkgDevel)
+import PackageUtils (rpmInstall, RpmStage (..), stripPkgDevel)
+import SysCmd (rpmEval)
+import Types
+
 import SimpleCmd (cmd_, (+-+))
 import SimpleCmd.Rpm (rpmspec)
-import SysCmd (rpmEval)
 
 #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
 #else
 --import Control.Applicative ((<$>))
 #endif
 import Control.Monad (unless, when)
-import System.Directory (removeDirectoryRecursive)
 import System.FilePath ((</>))
 
-install :: PackageData -> RpmFlags -> IO ()
-install pkgdata flags = do
-  let pkgDesc = packageDesc pkgdata
-  pkgInstallMissing flags pkgdata
-  stillMissing <- missingPackages pkgDesc
+install :: Flags -> PackageType -> Bool -> Stream -> Maybe Package -> IO ()
+install flags pkgtype subpackage stream mpkg = do
+  stillMissing <- pkgInstallMissing flags stream mpkg
   unless (null stillMissing) $ do
     putStrLn $ "Missing:" +-+ unwords stillMissing
     mapM_ cblrpmInstallMissing stillMissing
-  (spec, mtmpdir) <- rpmBuild pkgdata flags Binary
-  rpmdir <- rpmEval "%{_rpmdir}"
-  rpmspec [] (fmap (</> "%{arch}/%{name}-%{version}-%{release}.%{arch}.rpm") rpmdir) spec >>= rpmInstall
-  maybe (return ()) removeDirectoryRecursive mtmpdir
+  withTempDirectory $ \ _ -> do
+    spec <- rpmBuild Binary flags pkgtype subpackage stream mpkg
+    rpmdir <- rpmEval "%{_rpmdir}"
+    rpmspec [] (fmap (</> "%{arch}/%{name}-%{version}-%{release}.%{arch}.rpm") rpmdir) spec >>= rpmInstall False
 
 
 cblrpmInstallMissing :: String -> IO ()
diff --git a/src/Commands/Refresh.hs b/src/Commands/Refresh.hs
--- a/src/Commands/Refresh.hs
+++ b/src/Commands/Refresh.hs
@@ -18,12 +18,13 @@
 import Paths_cabal_rpm (version)
 import Commands.Spec (createSpecFile)
 import FileUtils (withTempDirectory)
-import Options (RpmFlags (..))
 import PackageUtils (PackageData (..), cabal_, patchSpec,
-                     removePrefix)
+                     prepare, removePrefix)
+import SysCmd (die, optionalProgram)
+import Types
+
 import SimpleCmd (cmd, cmd_, grep_)
 import SimpleCmd.Git (rwGitDir)
-import SysCmd (die, optionalProgram)
 
 #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
 #else
@@ -32,14 +33,16 @@
 import Control.Monad (unless, when)
 import Data.List (isPrefixOf)
 import Data.Version (showVersion)
+import Distribution.Verbosity (silent)
 import System.Directory (copyFile, createDirectoryIfMissing, doesFileExist,
                          renameFile, setCurrentDirectory)
 import System.Environment (getEnv)
 --import System.Exit (exitSuccess)
 import System.FilePath ((</>), (<.>))
 
-refresh :: PackageData -> RpmFlags -> IO ()
-refresh pkgdata flags =
+refresh :: Bool -> PackageType -> Stream -> Maybe Package -> IO ()
+refresh dryrun pkgtype stream mpkg = do
+  pkgdata <- prepare [] stream mpkg True
   case specFilename pkgdata of
     Nothing -> die "No (unique) .spec file in directory."
     Just spec -> do
@@ -50,19 +53,18 @@
           putStrLn "Working dir contain local changes!"
           -- exitSuccess
       first <- head . lines <$> readFile spec
-      do
-        let cblrpmver =
-              if "# generated by cabal-rpm-" `isPrefixOf` first
-              then removePrefix "# generated by cabal-rpm-" first
-              else "0.9.11"
-        if cblrpmver == showVersion version
-          then putStrLn "Packaging is up to date"
-          else do
-          subpkg <- grep_ "%{subpkgs}" spec
-          let flags' = if subpkg then flags {rpmSubpackage = True} else flags
-          oldspec <- createOldSpec subpkg cblrpmver spec
-          newspec <- createSpecFile pkgdata flags' Nothing
-          patchSpec Nothing oldspec newspec
+      -- filter "--subpackage", etc
+      let cblrpmver = head . words $
+            if "# generated by cabal-rpm-" `isPrefixOf` first
+            then removePrefix "# generated by cabal-rpm-" first
+            else "0.9.11"
+      if cblrpmver == showVersion version
+        then putStrLn "Packaging is up to date"
+        else do
+        subpkg <- grep_ "%{subpkgs}" spec
+        oldspec <- createOldSpec subpkg cblrpmver spec
+        newspec <- createSpecFile silent [] False pkgtype subpkg stream Nothing mpkg
+        patchSpec dryrun Nothing oldspec newspec
 --          setCurrentDirectory cwd
 --          when rwGit $
 --            cmd_ "git" ["commit", "-a", "-m", "refreshed to cabal-rpm-" ++ showVersion version]
@@ -99,4 +101,5 @@
           cmd_ "strip" [bin]
           copyFile bin $ bindir </> cblrpmver
           setCurrentDirectory cwd
-        cmd_ (bindir </> cblrpmver) $ ["--subpackage" | subpkg] ++ ["spec"]
+        -- Fixme 1.0.1 supports --quiet
+        cmd_ (bindir </> cblrpmver) $ "spec" : ["--subpackage" | subpkg]
diff --git a/src/Commands/RpmBuild.hs b/src/Commands/RpmBuild.hs
--- a/src/Commands/RpmBuild.hs
+++ b/src/Commands/RpmBuild.hs
@@ -20,11 +20,12 @@
     ) where
 
 import Commands.Spec (createSpecFile)
-import Dependencies (pkgInstallMissing)
-import FileUtils (mktempdir)
-import Options (RpmFlags (..))
-import PackageUtils (bringTarball, PackageData (..), packageName,
-                     packageVersion, rpmbuild, RpmStage (..))
+import Dependencies (pkgInstallMissing')
+import PackageUtils (bringTarball, PackageData (..), prepare,
+                     rpmbuild, RpmStage (..))
+import Types
+
+import SimpleCabal (showPkgId)
 import SimpleCmd ((+-+))
 
 #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
@@ -32,49 +33,28 @@
 import Control.Applicative ((<$>))
 #endif
 --import Control.Exception (bracket)
-import Control.Monad    (unless, when)
-import Data.Maybe (isNothing)
+import Control.Monad (void, when)
 import Distribution.PackageDescription (PackageDescription (..))
-import System.Directory (removeDirectoryRecursive)
-
---import Distribution.Version (VersionRange, foldVersionRange')
+import Distribution.Verbosity (normal)
 
--- autoreconf :: Verbosity -> PackageDescription -> IO ()
--- autoreconf verbose pkgDesc = do
---     ac <- doesFileExist "configure.ac"
---     when ac $ do
---         c <- doesFileExist "configure"
---         when (not c) $ do
---             setupMessage verbose "Running autoreconf" pkgDesc
---             cmd_ "autoreconf" []
+rpmBuild :: RpmStage -> Flags -> PackageType -> Bool -> Stream -> Maybe Package ->
+            IO FilePath
+rpmBuild stage flags pkgtype subpackage stream mpkg = do
+  pkgdata <- prepare flags stream mpkg True
+  when (stage == Binary) $
+    void $ pkgInstallMissing' pkgdata
 
-rpmBuild :: PackageData -> RpmFlags -> RpmStage ->
-            IO (FilePath, Maybe FilePath)
-rpmBuild pkgdata flags stage = do
---  let verbose = rpmVerbosity flags
---  bracket (setFileCreationMask 0o022) setFileCreationMask $ \ _ -> do
---    autoreconf verbose pkgDesc
   let pkgDesc = packageDesc pkgdata
       mspec = specFilename pkgdata
-  mtmp <- if isNothing mspec
-          then Just <$> mktempdir
-          else return Nothing
-  specFile <- maybe (createSpecFile pkgdata flags mtmp)
+  specFile <- maybe (createSpecFile normal flags False pkgtype subpackage stream Nothing mpkg)
               (\ s -> putStrLn ("Using existing" +-+ s) >> return s)
               mspec
   let pkg = package pkgDesc
-      name = packageName pkg
-  when (stage `elem` [Binary,BuildDep]) $
-    pkgInstallMissing flags pkgdata
-
-  unless (stage == BuildDep) $ do
-    let version = packageVersion pkg
-    bringTarball (name ++ "-" ++ version) True specFile
-    rpmbuild stage specFile
+  bringTarball (showPkgId pkg) True specFile
+  rpmbuild stage specFile
 
-  return (specFile, mtmp)
+  return specFile
 
-rpmBuild_ :: PackageData -> RpmFlags -> RpmStage -> IO ()
-rpmBuild_ pkgdata flags stage = do
-  (_, mtmpdir) <- rpmBuild pkgdata flags stage
-  maybe (return ()) removeDirectoryRecursive mtmpdir
+rpmBuild_ :: RpmStage -> Flags -> PackageType -> Bool -> Stream -> Maybe Package -> IO ()
+rpmBuild_ stage flags pkgtype subpackage stream mpkg =
+  void $ rpmBuild stage flags pkgtype subpackage stream mpkg
diff --git a/src/Commands/Spec.hs b/src/Commands/Spec.hs
--- a/src/Commands/Spec.hs
+++ b/src/Commands/Spec.hs
@@ -20,13 +20,15 @@
   createSpecFile, createSpecFile_
   ) where
 
-import Dependencies (notInstalled, missingPackages, packageDependencies,
-                     showDep, subPackages, testsuiteDependencies)
-import Distro (Distro(..), defaultRelease, detectDistro)
-import Options (RpmFlags (..))
+import Dependencies (ghcDep, LibPkgType(..), missingLibraries,
+                     missingOtherPkgs, notSrcOrInst,
+                     packageDependencies, pkgSuffix, subPackages,
+                     testsuiteDependencies')
+import Types
 import PackageUtils (bringTarball, getPkgName, latestPackage,
                      PackageData (..), packageName, packageVersion,
-                     prettyShow, stripPkgDevel)
+                     prepare, removePrefix)
+import SimpleCabal (mkPackageName, PackageName, showVersion, unPackageName)
 import SimpleCmd ((+-+))
 
 import Control.Monad    (filterM, unless, void, when, (>=>))
@@ -42,7 +44,7 @@
 import Data.Maybe       (isJust, fromMaybe, fromJust)
 import Data.Time.Clock  (getCurrentTime)
 import Data.Time.Format (formatTime)
-import Data.Version (showVersion)
+import qualified Data.Version as V
 
 import Distribution.License  (License (..)
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,2,0)
@@ -56,19 +58,13 @@
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,2,0)
                                         license,
 #endif
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-                                        unFlagName
-#else
-                                        FlagName (..)
-#endif
                                        )
-import Distribution.Simple.Utils (notice, warn)
+import Distribution.Simple.Utils (warn)
 
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
 import Distribution.Types.UnqualComponentName (unUnqualComponentName)
 #endif
-
---import Distribution.Version (VersionRange, foldVersionRange')
+import Distribution.Verbosity (Verbosity)
 
 import System.Directory (doesFileExist)
 import System.IO     (IOMode (..), hClose, hPutStrLn, openFile)
@@ -87,30 +83,28 @@
 
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
 #else
-unFlagName :: FlagName -> String
-unFlagName (FlagName n) = n
-
 unUnqualComponentName :: String -> String
 unUnqualComponentName = id
 #endif
 
-createSpecFile :: PackageData -> RpmFlags ->
-                  Maybe FilePath -> IO FilePath
-createSpecFile pkgdata flags mdest = do
-  let mspec = specFilename pkgdata
+createSpecFile :: Verbosity -> Flags -> Bool -> PackageType -> Bool -> Stream -> Maybe FilePath -> Maybe Package -> IO FilePath
+createSpecFile verbose flags force pkgtype subpackage stream mdest mpkg = do
+  pkgdata <- prepare flags stream mpkg True
+  let mspec = case pkgtype of
+                SpecFile f -> Just f
+                _ -> specFilename pkgdata
       docs = docFilenames pkgdata
       licensefiles = licenseFilenames pkgdata
       pkgDesc = packageDesc pkgdata
       pkg = package pkgDesc
-      name = packageName pkg
-      verbose = rpmVerbosity flags
+      name = unPackageName $ packageName pkg
+      standalone = pkgtype == StandalonePkg
       hasExec = hasExes pkgDesc
       hasLib = hasLibs pkgDesc
       hasLibPkg = hasLib && not standalone
       dupdocs = docs `intersect` dataFiles pkgDesc
       datafiles = dataFiles pkgDesc \\ dupdocs
-      standalone = rpmStandalone flags
-  (pkgname, binlib) <- getPkgName mspec pkgDesc (rpmBinary flags || standalone)
+  (pkgname, binlib) <- getPkgName mspec pkgDesc (pkgtype == BinaryPkg || standalone)
   let pkg_name = if pkgname == name then "%{name}" else "%{pkg_name}"
       basename | binlib = "%{pkg_name}"
                | hasExecPkg = name
@@ -119,13 +113,12 @@
       hasExecPkg = binlib || (hasExec && not hasLibPkg)
   -- run commands before opening file to prevent empty file on error
   -- maybe shell commands should be in a monad or something
-  (deps, tools, clibs, pkgcfgs) <- packageDependencies (rpmStrict flags) pkgDesc
-  let testsuiteDeps = testsuiteDependencies pkgDesc name
+  (deps, setupDeps, tools, clibs, pkgcfgs) <- packageDependencies pkgDesc
 
   specAlreadyExists <- doesFileExist specFile
-  let specFile' = specFile ++ if not (rpmForce flags) && specAlreadyExists then ".cblrpm" else ""
+  let specFile' = specFile ++ if not force && specAlreadyExists then ".cblrpm" else ""
   if specAlreadyExists
-    then notice verbose $ specFile +-+ "exists:" +-+ if rpmForce flags then "forcing overwrite" else "creating" +-+ specFile'
+    then warn verbose $ specFile +-+ "exists:" +-+ (if force then "forcing overwrite" else "creating") +-+ specFile'
     else do
     let realdir dir = "cblrpm." `isPrefixOf` takeBaseName dir
     when (maybe True realdir mdest) $
@@ -139,33 +132,11 @@
       sectionNewline = putNewline >> putNewline
       put = hPutStrLn h
       global m v = put $ "%global" +-+ m +-+ v
-      ghcPkg = if binlib then "-n ghc-%{name}" else ""
-      ghcPkgDevel = if binlib then "-n ghc-%{name}-devel" else "devel"
+      subpkgParam lt = if binlib then "-n ghc-%{name}" ++ pkgSuffix lt else show lt
 
-  put $ "# generated by cabal-rpm-" ++ showVersion Paths_cabal_rpm.version
-    +-+ unwords (["--missing" | rpmMissing flags] ++ ["--standalone" | standalone] ++ ["--subpackage" | rpmSubpackage flags])
-  distro <- maybe detectDistro return (rpmDistribution flags)
-  if distro /= SUSE
-    then put "# https://fedoraproject.org/wiki/Packaging:Haskell"
-    else do
-    now <- getCurrentTime
-    let year = formatTime defaultTimeLocale "%Y" now
-    put "#"
-    put $ "# spec file for package " ++ pkgname
-    put "#"
-    put $ "# Copyright (c) " ++ year ++ " SUSE LINUX GmbH, Nuernberg, Germany."
-    put "#"
-    put "# All modifications and additions to the file contributed by third parties"
-    put "# remain the property of their copyright owners, unless otherwise agreed"
-    put "# upon. The license for this file, and modifications and additions to the"
-    put "# file, is the same license as for the pristine package itself (unless the"
-    put "# license for the pristine package is not an Open Source License, in which"
-    put "# case the license is the MIT License). An \"Open Source License\" is a"
-    put "# license that conforms to the Open Source Definition (Version 1.9)"
-    put "# published by the Open Source Initiative."
-    putNewline
-    put "# Please submit bugfixes or comments via http://bugs.opensuse.org/"
-    put "#"
+  put $ "# generated by cabal-rpm-" ++ V.showVersion Paths_cabal_rpm.version
+    +-+ unwords (["--standalone" | standalone] ++ ["--subpackage" | subpackage])
+  put "# https://fedoraproject.org/wiki/Packaging:Haskell"
   putNewline
 
   -- Some packages conflate the synopsis and description fields.  Ugh.
@@ -211,46 +182,40 @@
 
   -- FIXME sort by build order
   -- FIXME recursive missingdeps
-  missing <- do
-    subs <- if rpmSubpackage flags then subPackages mspec pkgDesc else return []
-    miss <- if rpmSubpackage flags || rpmMissing flags || standalone then missingPackages pkgDesc else return []
+  missingLibs <- do
+    subs <- if subpackage then subPackages mspec pkgDesc else return []
+    miss <- if subpackage || standalone then missingLibraries pkgDesc else return []
     return $ nub (subs ++ miss)
-  subpkgs <- if rpmSubpackage flags then
-    mapM ((getsubpkgMacro flags specFile >=>
-           \(m,pv) -> global m pv >> return ("%{" ++ m ++ "}"))
-           . stripPkgDevel) missing
+  subpkgs <- if subpackage then
+    mapM (getsubpkgMacro stream specFile >=>
+           \(m,pv) -> global m pv >> return ("%{" ++ m ++ "}")) missingLibs
     else return []
   let hasSubpkgs = subpkgs /= []
   when hasSubpkgs $ do
     global "subpkgs" $ unwords subpkgs
     putNewline
 
+  let testsuiteDeps = testsuiteDependencies' pkgDesc
   unless (null testsuiteDeps) $ do
-    missTestDeps <- filterM notInstalled testsuiteDeps
+    missTestDeps <- filterM notSrcOrInst $ map (ghcDep LibDevel) testsuiteDeps
     put $ "%bcond_" ++ (if null missTestDeps then "without" else "with") +-+ "tests"
     putNewline
 
   let version = packageVersion pkg
-      defRelease = defaultRelease distro
-      release = fromMaybe defRelease (rpmRelease flags)
+      release = "1"
       revised = isJust $ lookup "x-revision" (customFieldsPD pkgDesc)
   putHdr "Name" (if binlib then "%{pkg_name}" else basename)
   putHdr "Version" version
   when hasSubpkgs $
     put "# can only be reset when all subpkgs bumped"
-  putHdr "Release" $ release ++ (if distro == SUSE then [] else "%{?dist}")
+  putHdr "Release" $ release ++ "%{?dist}"
   putHdr "Summary" summary
-  case distro of
-    SUSE -> putHdr "Group" "Development/Languages/Other"
-    RHEL5 -> putHdr "Group" (if binlib then "Development/Languages"
-                            else "System Environment/Libraries")
-    _ -> return ()
   putNewline
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,2,0)
 #else
   let licenseFromSPDX = id
 #endif
-  putHdr "License" $ (showLicense distro . licenseFromSPDX . license) pkgDesc
+  putHdr "License" $ (showLicense . licenseFromSPDX . license) pkgDesc
   putHdr "Url" $ "https://hackage.haskell.org/package" </> pkg_name
   put "# Begin cabal-rpm sources:"
   putHdr "Source0" $ sourceUrl pkgver
@@ -258,26 +223,34 @@
   when revised $
     putHdr ("Source" ++ show (1 + length subpkgs)) $ "https://hackage.haskell.org/package" </> pkgver </> pkg_name <.> "cabal" ++ "#" </> pkgver <.> "cabal"
   put "# End cabal-rpm sources"
-  case distro of
-    Fedora -> return ()
-    _ -> putHdr "BuildRoot" "%{_tmppath}/%{name}-%{version}-build"
   putNewline
   put "# Begin cabal-rpm deps:"
-  putHdr "BuildRequires" "ghc-Cabal-devel"
+  when (mkPackageName "Cabal" `notElem` deps || not hasLib || not (null setupDeps)) $ do
+--    put "# Setup"
+  -- `not hasLib` is for -static
+    when (mkPackageName "Cabal" `notElem` deps {-|| not hasLib-}) $
+      putHdr "BuildRequires" "ghc-Cabal-devel"
+    mapM_ (\ d -> (if d `elem` missingLibs then putHdrComment else putHdr) "BuildRequires" (ghcDep LibDevel d)) setupDeps
   putHdr "BuildRequires" $ "ghc-rpm-macros" ++ (if hasSubpkgs then "-extra" else "")
 
-  let alldeps = sort $ deps ++ tools ++ clibs ++ pkgcfgs ++ ["chrpath" | hasSubpkgs]
-  let testDeps = sort $ testsuiteDeps \\ deps
-  unless (null $ alldeps ++ testDeps) $ do
-    mapM_ (\ d -> (if d `elem` missing then putHdrComment else putHdr) "BuildRequires" d) alldeps
-    -- for ghc < 7.8
-    when (distro `notElem` [Fedora, SUSE] &&
-          any (\ d -> d `elem` map showDep ["template-haskell", "hamlet"]) deps) $
-      putHdr "ExclusiveArch" "%{ghc_arches_with_ghci}"
-    unless (null testDeps) $ do
-      put "%if %{with tests}"
-      mapM_ (putHdr "BuildRequires") testDeps
-      put "%endif"
+  unless (null deps) $ do
+--    put "# Build"
+    let ghcLibDep = ghcDep $ if hasLibPkg then LibProf else LibStatic
+    mapM_ (\ d -> (if d `elem` missingLibs then putHdrComment else putHdr) "BuildRequires" (ghcLibDep d)) $ sort deps
+  let otherdeps = sort $ tools ++ clibs ++ pkgcfgs
+  unless (null otherdeps) $ do
+--    put "# Other"
+    missingOthers <- missingOtherPkgs pkgDesc
+    mapM_ (\ d -> (if d `elem` missingOthers then putHdrComment else putHdr) "BuildRequires" d) otherdeps
+    -- -- for ghc < 7.8:
+    -- when (epel7 &&
+    --       any (\ d -> d `elem` map showDep ["template-haskell", "hamlet"]) deps) $
+    --   putHdr "ExclusiveArch" "%{ghc_arches_with_ghci}"
+  let testDeps = sort $ testsuiteDeps \\ (mkPackageName "Cabal" : (deps ++ setupDeps))
+  unless (null testDeps) $ do
+    put "%if %{with tests}"
+    mapM_ (putHdr "BuildRequires" . ghcDep LibDevel) testDeps
+    put "%endif"
 
   let common = binlib && datafiles /= [] && not standalone
   when common $
@@ -291,7 +264,7 @@
   mapM_ put descLines
   putNewline
 
-  let wrapGenDesc = wordwrap (79 - max 0 (length pkgname - length pkg_name))
+  let wrapGenDesc = init . wordwrap (79 - max 0 (length pkgname - length pkg_name))
 
   when common $ do
     put "%package common"
@@ -300,56 +273,62 @@
     putNewline
     put "%description common"
     put $ wrapGenDesc $ "This package provides the" +-+ pkg_name +-+ "common data files."
-    putNewline
+    sectionNewline
 
   -- haskell-gi generates lib source files at configure time
-  -- (stricly should also check for otherModules (autogenModules?)
+  -- (strictly should also check for otherModules (autogenModules?)
   --  but libraries wihout exposedModules should be useless/redundant)
   let hasModules =
-        hasLib && ((notNull . exposedModules . fromJust . library) pkgDesc || "ghc-haskell-gi-devel" `elem` deps)
+        hasLib && ((notNull . exposedModules . fromJust . library) pkgDesc || mkPackageName "haskell-gi" `elem` (deps ++ setupDeps))
 
   when hasLibPkg $ do
     when (binlib && hasModules) $ do
-      put $ "%package" +-+ ghcPkg
+      put $ "%package" +-+ subpkgParam LibBase
       putHdr "Summary" $ "Haskell" +-+ pkg_name +-+ "library"
-      case distro of
-        SUSE -> putHdr "Group" "System/Libraries"
-        RHEL5 -> putHdr "Group" "System Environment/Libraries"
-        _ -> return ()
       when common $
         putHdr "Requires" "%{name}-common = %{version}-%{release}"
       putNewline
-      put $ "%description" +-+ ghcPkg
+      put $ "%description" +-+ subpkgParam LibBase
       put $ wrapGenDesc $ "This package provides the Haskell" +-+ pkg_name +-+ "shared library."
-      putNewline
-    put $ "%package" +-+ ghcPkgDevel
+      sectionNewline
+    let isa = "%{?_isa}"
+    put $ "%package" +-+ subpkgParam LibDevel
     putHdr "Summary" $ "Haskell" +-+ pkg_name +-+ "library development files"
-    case distro of
-      RHEL5 -> putHdr "Group" "Development/Libraries"
-      SUSE -> putHdr "Group" "Development/Libraries/Other"
-      _ -> return ()
-    unless (distro == SUSE) $
-      putHdr "Provides" $ (if binlib then "ghc-%{name}" else "%{name}") ++ "-static = %{version}-%{release}"
-    when hasModules $
-      putHdr "Provides" $ (if binlib then "ghc-%{name}" else "%{name}") ++ "-doc" +-+ "= %{version}-%{release}"
+    putHdr "Provides" $ (if binlib then "ghc-%{name}" else "%{name}") ++ "-static = %{version}-%{release}"
+    putHdr "Provides" $ (if binlib then "ghc-%{name}" else "%{name}") ++ "-static" ++ isa +-+ "= %{version}-%{release}"
     put "%if %{defined ghc_version}"
     putHdr "Requires" "ghc-compiler = %{ghc_version}"
-    putHdr "Requires(post)" "ghc-compiler = %{ghc_version}"
-    putHdr "Requires(postun)" "ghc-compiler = %{ghc_version}"
     put "%endif"
-    let isa = if distro == SUSE then "" else "%{?_isa}"
     when hasModules $
       putHdr "Requires" $ (if binlib then "ghc-%{name}" else "%{name}") ++ isa +-+ "= %{version}-%{release}"
     unless (null $ clibs ++ pkgcfgs) $ do
       put "# Begin cabal-rpm deps:"
-      mapM_ (putHdr "Requires") $ sort $ map (++ isa) clibs ++ pkgcfgs ++ ["pkgconfig" | distro == SUSE, pkgcfgs /= []]
+      mapM_ (putHdr "Requires") $ sort $ map (++ isa) clibs ++ pkgcfgs
       put "# End cabal-rpm deps"
     putNewline
-    put $ "%description" +-+ ghcPkgDevel
+    put $ "%description" +-+ subpkgParam LibDevel
     put $ wrapGenDesc $ "This package provides the Haskell" +-+ pkg_name +-+ "library development files."
-    -- previous line ends in an extra newline
+    sectionNewline
+-- ? when hasModules $
+    put "%if %{with haddock}"
+    put $ "%package" +-+ subpkgParam LibDoc
+    putHdr "Summary" $ "Haskell" +-+ pkg_name +-+ "library documentation"
     putNewline
+    put $ "%description" +-+ subpkgParam LibDoc
+    put $ wrapGenDesc $ "This package provides the Haskell" +-+ pkg_name +-+ "library documentation."
+    put "%endif"
+    sectionNewline
 
+    put "%if %{with ghc_prof}"
+    put $ "%package" +-+ subpkgParam LibProf
+    putHdr "Summary" $ "Haskell" +-+ pkg_name +-+ "profiling library"
+    putHdr "Requires" $ (if binlib then "ghc-%{name}" else "%{name}") ++ "-devel" ++ isa +-+ "= %{version}-%{release}"
+    putNewline
+    put $ "%description" +-+ subpkgParam LibProf
+    put $ wrapGenDesc $ "This package provides the Haskell" +-+ pkg_name +-+ "profiling library."
+    put "%endif"
+    sectionNewline
+
   when hasSubpkgs $ do
     global "main_version" "%{version}"
     putNewline
@@ -378,12 +357,9 @@
     put "%cabal update"
     put "%cabal sandbox init"
     put "%cabal install --only-dependencies"
-  when (distro == SUSE && rpmConfigurationsFlags flags /= []) $ do
-    let cabalFlags = [ "-f" ++ (if b then "" else "-") ++ unFlagName n | (n, b) <- rpmConfigurationsFlags flags ]
-    put $ "%define cabal_configure_options " ++ unwords cabalFlags
   let pkgType = if hasLibPkg then "lib" else "bin"
   put $ "%ghc_" ++ pkgType ++ "_build" ++
-        if hasLibPkg && not hasModules then "_build_without_haddock" else []
+        if hasLibPkg && not hasModules then "_without_haddock" else []
   put "# End cabal-rpm build"
   sectionNewline
 
@@ -399,11 +375,10 @@
   unless (null dupdocs) $ do
     putNewline
     putStrLn $ "Warning: doc files found in datadir:" +-+ unwords dupdocs
-    unless (distro == SUSE) $
-      put $ "rm %{buildroot}%{_datadir}" </> pkgver </>
-        case length dupdocs of
-           1 -> head dupdocs
-           _ -> "{" ++ intercalate "," dupdocs ++ "}"
+    put $ "rm %{buildroot}%{_datadir}" </> pkgver </>
+      case length dupdocs of
+         1 -> head dupdocs
+         _ -> "{" ++ intercalate "," dupdocs ++ "}"
 
   when (hasLibPkg && not hasModules) $
     put "mv %{buildroot}%{_ghcdocdir}{,-devel}"
@@ -411,13 +386,12 @@
   when common $
     put "mv %{buildroot}%{_ghcdocdir}{,-common}"
 
-  put "# End cabal-rpm install"
-
   when (standalone && hasLib) $ do
     -- can be dropped with ghc-rpm-macros-1.9.8
     put "find %{buildroot}%{_libdir} -name 'libHS%{pkgver}-*.so' -delete"
     put "rm -r %{buildroot}%{ghclibdir}"
 
+  put "# End cabal-rpm install"
   sectionNewline
 
   unless (null testsuiteDeps) $ do
@@ -425,22 +399,12 @@
     put "%cabal_test"
     sectionNewline
 
-  when hasLibPkg $ do
-    put $ "%post" +-+ ghcPkgDevel
-    put "%ghc_pkg_recache"
-    sectionNewline
-
-    put $ "%postun" +-+ ghcPkgDevel
-    put "%ghc_pkg_recache"
-    sectionNewline
-
-  let license_macro = if distro == Fedora then "%license" else "%doc"
+  let license_macro = "%license"
   let execs = sort $ map exeName $ filter isBuildable $ executables pkgDesc
 
   when hasExecPkg $ do
     put "%files"
     put "# Begin cabal-rpm files:"
-    when (distro /= Fedora) $ put "%defattr(-,root,root,-)"
     -- Add the license file to the main package only if it wouldn't
     -- otherwise be empty.
     unless common $ do
@@ -456,7 +420,6 @@
   when common $ do
     put "%files common"
     put "# Begin cabal-rpm files:"
-    when (distro /= Fedora) $ put "%defattr(-,root,root,-)"
     mapM_ (\ l -> put $ license_macro +-+ l) licensefiles
     unless (null docs) $
       put $ "%doc" +-+ unwords docs
@@ -465,89 +428,80 @@
     sectionNewline
 
   when hasLibPkg $ do
-    let baseFiles = if binlib then "-f ghc-%{name}.files" else "-f %{name}.files"
-        develFiles = if binlib then "-f ghc-%{name}-devel.files" else "-f %{name}-devel.files"
+    let filesParams lt = subpkgParam lt +-+ "-f" +-+ (if binlib then "ghc-" else "" ) ++ "%{name}" ++ pkgSuffix lt ++ ".files"
     when hasModules $ do
-      put $ "%files" +-+ ghcPkg +-+ baseFiles
-      put "# Begin cabal-rpm files:"
-      when (distro /= Fedora) $ put "%defattr(-,root,root,-)"
-      unless common $
+      put $ "%files" +-+ filesParams LibBase
+      unless common $ do
+        put "# Begin cabal-rpm files:"
         mapM_ (\ l -> put $ license_macro +-+ l) licensefiles
-      when (distro == SUSE && not binlib) $
-        mapM_ ((\ p -> put $ "%{_bindir}" </> (if p == name then "%{pkg_name}" else p)) . unUnqualComponentName) execs
-      unless (common || null datafiles) $
-        put $ "%{_datadir}" </> pkgver
-      put "# End cabal-rpm files"
+        unless (null datafiles) $
+          put $ "%{_datadir}" </> pkgver
+        put "# End cabal-rpm files"
       sectionNewline
 
-    put $ "%files" +-+ ghcPkgDevel +-+  develFiles
+    put $ "%files" +-+ filesParams LibDevel
     -- put "# Begin cabal-rpm files:"
-    when (distro /= Fedora) $ put "%defattr(-,root,root,-)"
     unless hasModules $
       mapM_ (\ l -> put $ license_macro +-+ l) licensefiles
     unless (common || null docs) $
       put $ "%doc" +-+ unwords docs
-    when (distro /= SUSE && not binlib) $
+    unless binlib $
       mapM_ ((\ p -> put $ "%{_bindir}" </> (if p == name then "%{pkg_name}" else p)) . unUnqualComponentName) execs
     -- put "# End cabal-rpm files"
     sectionNewline
 
+    put "%if %{with haddock}"
+    put $ "%files" +-+ filesParams LibDoc
+    put "%endif"
+    sectionNewline
+    put "%if %{with ghc_prof}"
+    put $ "%files" +-+ filesParams LibProf
+    put "%endif"
+    sectionNewline
+
   put "%changelog"
-  unless (distro == SUSE) $ do
-    now <- getCurrentTime
-    let date = formatTime defaultTimeLocale "%a %b %e %Y" now
-    put $ "*" +-+ date +-+ "Fedora Haskell SIG <haskell@lists.fedoraproject.org> - " ++ version ++ "-" ++ release
-    put $ "- spec file generated by cabal-rpm-" ++ showVersion Paths_cabal_rpm.version
+  now <- getCurrentTime
+  let date = formatTime defaultTimeLocale "%a %b %e %Y" now
+  put $ "*" +-+ date +-+ "Fedora Haskell SIG <haskell@lists.fedoraproject.org> - " ++ version ++ "-" ++ release
+  put $ "- spec file generated by cabal-rpm-" ++ V.showVersion Paths_cabal_rpm.version
   hClose h
   return specFile'
 
-createSpecFile_ :: PackageData -> RpmFlags ->
-                   Maybe FilePath -> IO ()
-createSpecFile_ pkgFiles flags mdest =
-  void (createSpecFile pkgFiles flags mdest)
+createSpecFile_ :: Maybe FilePath -> Verbosity -> Flags -> Bool -> PackageType -> Bool -> Stream -> Maybe Package -> IO ()
+createSpecFile_ mdest verbose flags force pkgtype subpackage stream mpkg =
+  void (createSpecFile verbose flags force pkgtype subpackage stream mdest mpkg)
 
 isBuildable :: Executable -> Bool
 isBuildable exe = buildable $ buildInfo exe
 
-showLicense :: Distro -> License -> String
-showLicense SUSE (GPL Nothing) = "GPL-1.0+"
-showLicense _    (GPL Nothing) = "GPL+"
-showLicense SUSE (GPL (Just ver)) = "GPL-" ++ prettyShow ver ++ "+"
-showLicense _    (GPL (Just ver)) = "GPLv" ++ prettyShow ver ++ "+"
-showLicense SUSE (LGPL Nothing) = "LGPL-2.0+"
-showLicense _    (LGPL Nothing) = "LGPLv2+"
-showLicense SUSE (LGPL (Just ver)) = "LGPL-" ++ prettyShow ver ++ "+"
-showLicense _    (LGPL (Just ver)) = "LGPLv" ++ [head $ prettyShow ver] ++ "+"
-showLicense SUSE BSD3 = "BSD-3-Clause"
-showLicense _    BSD3 = "BSD"
-showLicense SUSE BSD4 = "BSD-4-Clause"
-showLicense _    BSD4 = "BSD"
-showLicense _ MIT = "MIT"
-showLicense SUSE PublicDomain = "SUSE-Public-Domain"
-showLicense _    PublicDomain = "Public Domain"
-showLicense SUSE AllRightsReserved = "SUSE-NonFree"
-showLicense _    AllRightsReserved = "Proprietary"
-showLicense _ OtherLicense = "Unknown"
-showLicense _ (UnknownLicense l) = l
+showLicense :: License -> String
+showLicense (GPL Nothing) = "GPL+"
+showLicense (GPL (Just ver)) = "GPLv" ++ showVersion ver ++ "+"
+showLicense (LGPL Nothing) = "LGPLv2+"
+showLicense (LGPL (Just ver)) = "LGPLv" ++ [head $ showVersion ver] ++ "+"
+showLicense BSD3 = "BSD"
+showLicense BSD4 = "BSD"
+showLicense MIT = "MIT"
+showLicense PublicDomain = "Public Domain"
+showLicense AllRightsReserved = "Proprietary"
+showLicense OtherLicense = "Unknown"
+                           -- FIXME
+showLicense (UnknownLicense l) = removePrefix "LicenseRef" l
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,16,0)
-showLicense SUSE (Apache Nothing) = "Apache-2.0"
-showLicense _    (Apache Nothing) = "ASL ?"
-showLicense SUSE (Apache (Just ver)) = "Apache-" ++ prettyShow ver
-showLicense _    (Apache (Just ver)) = "ASL" +-+ prettyShow ver
+showLicense (Apache Nothing) = "ASL ?"
+showLicense (Apache (Just ver)) = "ASL" +-+ showVersion ver
 #endif
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,18,0)
-showLicense _ (AGPL Nothing) = "AGPLv?"
-showLicense _ (AGPL (Just ver)) = "AGPLv" ++ prettyShow ver
+showLicense (AGPL Nothing) = "AGPLv?"
+showLicense (AGPL (Just ver)) = "AGPLv" ++ showVersion ver
 #endif
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,20,0)
-showLicense SUSE BSD2 = "BSD-2-Clause"
-showLicense _ BSD2 = "BSD"
-showLicense SUSE (MPL ver) = "MPL-" ++ prettyShow ver
-showLicense _ (MPL ver) = "MPLv" ++ prettyShow ver
+showLicense BSD2 = "BSD"
+showLicense (MPL ver) = "MPLv" ++ showVersion ver
 #endif
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,22,0)
-showLicense _ ISC = "ISC"
-showLicense _ UnspecifiedLicense = "Unspecified license!"
+showLicense ISC = "ISC"
+showLicense UnspecifiedLicense = "Unspecified license!"
 #endif
 
 sourceUrl :: String -> String
@@ -576,10 +530,10 @@
     paragraphs :: [String] -> [String]
     paragraphs = map (unlines . filter notNull) . groupBy (const notNull)
 
-getsubpkgMacro :: RpmFlags -> FilePath -> String -> IO (String, String)
-getsubpkgMacro flags spec pkg = do
-  let macro = filter (/= '-') pkg
-  pkgver <- latestPackage (rpmStream flags) pkg
+getsubpkgMacro :: Stream -> FilePath -> PackageName -> IO (String, String)
+getsubpkgMacro stream spec pkg = do
+  let macro = filter (/= '-') $ unPackageName pkg
+  pkgver <- latestPackage stream pkg
   bringTarball pkgver False spec
   return (macro, pkgver)
 
diff --git a/src/Commands/Update.hs b/src/Commands/Update.hs
--- a/src/Commands/Update.hs
+++ b/src/Commands/Update.hs
@@ -17,29 +17,31 @@
   ) where
 
 import Commands.Spec (createSpecFile)
-import Distro (defaultRelease, detectDistro, Distro(..))
 import FileUtils (withTempDirectory)
-import Options (RpmFlags (..))
 import PackageUtils (PackageData (..), bringTarball, editSpecField,
                      getRevisedCabal, getSpecField, latestPackage, packageName,
-                     packageVersion, patchSpec, prepare, readVersion,
-                     removePrefix, removeSuffix)
+                     packageVersion, patchSpec, prepare,
+                     readVersion, removePrefix, removeSuffix)
+import SysCmd (die)
+import Types
+
+import SimpleCabal (showPkgId, unPackageName)
 import SimpleCmd (cmd_, grep_, shell_, (+-+))
 import SimpleCmd.Git (rwGitDir)
-import SysCmd (die)
 #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
 #else
 import Control.Applicative ((<$>))
 #endif
 import Control.Monad (unless, when)
-import Data.List (isPrefixOf)
 import Data.Maybe (isJust)
 import Distribution.PackageDescription (PackageDescription (..))
+import Distribution.Verbosity (silent)
 import System.Directory (createDirectory, renameFile, setCurrentDirectory)
 import System.FilePath ((</>), (<.>))
 
-update :: PackageData -> RpmFlags -> Maybe String -> IO ()
-update pkgdata flags mpkgver =
+update :: Stream -> Maybe String -> IO ()
+update stream mver = do
+  pkgdata <- prepare [] stream Nothing True
   case specFilename pkgdata of
     Nothing -> die "No (unique) .spec file in directory."
     Just spec -> do
@@ -48,12 +50,12 @@
           name = packageName pkg
           ver = packageVersion pkg
           curVer = readVersion ver
-          current = name ++ "-" ++ ver
+          current = showPkgId pkg
           revised = isJust $ lookup "x-revision" (customFieldsPD pkgDesc)
-      latest <- case mpkgver of
-                    Just pv | (name ++ "-") `isPrefixOf` pv -> return pv
-                    _ -> latestPackage (rpmStream flags) name
-      let newver = removePrefix (name ++ "-") latest
+      latest <- case mver of
+                    Just v -> return v
+                    _ -> latestPackage stream name
+      let newver = removePrefix (unPackageName name ++ "-") latest
           latestVer = readVersion newver
           updated = latestVer > curVer
       if latestVer < curVer
@@ -68,12 +70,11 @@
             subpkg <- grep_ "%{subpkgs}" specfile
             (curspec, _) <- createSpecVersion current specfile revised subpkg
             (newspec, newrevised) <- createSpecVersion latest specfile True subpkg
-            distro <- maybe detectDistro return (rpmDistribution flags)
-            let suffix = if distro == SUSE then "" else "%{?dist}"
-                defrelease = defaultRelease distro
+            let suffix = "%{?dist}"
+                defrelease = "1"
             currel <- removeSuffix suffix <$> getSpecField "Release" specfile
             editSpecField "Release" (defrelease ++ suffix) specfile
-            patchSpec (Just cwd) curspec newspec
+            patchSpec False (Just cwd) curspec newspec
             ver' <- getSpecField "Version" specfile
             when (ver' /= newver) $
               editSpecField "Version" newver specfile
@@ -81,11 +82,10 @@
               then editSpecField "Release" (defrelease ++ suffix) specfile
               else editSpecField "Release" (currel ++ suffix) specfile
             when updated $ do
-              when (distro /= SUSE) $ do
-                -- FIXME reset when all subpkgs updated
-                unless subpkg $
-                  editSpecField "Release" ("0" ++ suffix) specfile
-                cmd_ "rpmdev-bumpspec" ["-c", "update to" +-+ newver, specfile]
+              -- FIXME reset when all subpkgs updated
+              unless subpkg $
+                editSpecField "Release" ("0" ++ suffix) specfile
+              cmd_ "rpmdev-bumpspec" ["-c", "update to" +-+ newver, specfile]
               setCurrentDirectory cwd
               rwGit <- rwGitDir
               when (rwGit && subpkg) $ do
@@ -105,12 +105,11 @@
   where
     createSpecVersion :: String -> String -> Bool -> Bool -> IO (FilePath, Bool)
     createSpecVersion pkgver spec revise subpkg = do
-      let flags' = flags { rpmSubpackage = subpkg }
-      pd <- prepare flags' (Just pkgver) revise
+      pd <- prepare [] stream (Just pkgver) revise
       let pkgdata' = pd { specFilename = Just spec }
-          dir = pkgver <.> if revise then "" else "orig"
+          dir = pkgver ++ if revise then ".revised" else ".orig"
       createDirectory dir
-      newspec <- createSpecFile pkgdata' flags' (Just dir)
+      newspec <- createSpecFile silent [] False (SpecFile spec) subpkg stream (Just dir) (Just pkgver)
       let newrevised =
             let pkgDesc = packageDesc pkgdata' in
               isJust $ lookup "x-revision" (customFieldsPD pkgDesc)
diff --git a/src/Dependencies.hs b/src/Dependencies.hs
--- a/src/Dependencies.hs
+++ b/src/Dependencies.hs
@@ -17,19 +17,29 @@
 
 module Dependencies (
   dependencies,
+  ghcDep,
+  LibPkgType(..),
+  missingLibraries,
+  missingOtherPkgs,
   missingPackages,
   notInstalled,
+  notSrcOrInst,
   packageDependencies,
   pkgInstallMissing,
-  showDep,
+  pkgInstallMissing',
+  pkgSuffix,
   subPackages,
-  testsuiteDependencies
+  testsuiteDependencies'
   ) where
 
-import Options (RpmFlags(..))
-import PackageUtils (PackageData(..), packageName, removeSuffix, repoquery,
-                     rpmInstall, stripPkgDevel)
-import SimpleCmd (cmd, cmdBool, (+-+))
+import PackageUtils (PackageData(..), prepare, removeLibSuffix,
+                     repoquery, rpmInstall, stripPkgDevel)
+import Types
+
+import SimpleCabal (buildDependencies, mkPackageName, exeDepName,
+                    PackageName, pkgcfgDepName, pkgName,
+                    setupDependencies, testsuiteDependencies, unPackageName)
+import SimpleCmd (cmd, cmdBool, warning, (+-+))
 import SimpleCmd.Rpm (rpmspec)
 
 #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
@@ -41,102 +51,48 @@
 import Data.List (delete, isPrefixOf, isSuffixOf, nub, (\\))
 import Data.Maybe (catMaybes, fromJust, isNothing)
 
-import Distribution.Package  (Dependency (..),
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,22,0)
-                              unPackageName,
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-                              unPkgconfigName
-#endif
-#else
-                              PackageName (..)
-#endif
-                                       )
-
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,4,0)
-import Distribution.Types.ComponentRequestedSpec (defaultComponentRequestedSpec)
-#endif
-import Distribution.Types.LegacyExeDependency (LegacyExeDependency (..))
-import Distribution.Types.PkgconfigDependency (PkgconfigDependency (..))
-#endif
-
 import Distribution.PackageDescription (PackageDescription (..),
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,4,0)
-                                        enabledBuildDepends,
-#endif
                                         allBuildInfo,
                                         BuildInfo (..),
-                                        TestSuite (..),
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,24,0)
-                                        setupDepends
-#endif
                                         )
 import System.Directory (doesDirectoryExist, doesFileExist)
 import System.FilePath ((<.>), (</>))
-import System.IO (hPutStrLn, stderr)
 
-excludedPkgs :: String -> Bool
-excludedPkgs = flip notElem ["Cabal", "base", "ghc-prim", "integer-gmp"]
-
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,4,0)
-buildDepends :: PackageDescription -> [Dependency]
-buildDepends = flip enabledBuildDepends defaultComponentRequestedSpec
-#else
-#endif
-
--- returns list of deps
-buildDependencies :: PackageDescription -> String -> [String]
-buildDependencies pkgDesc self =
-  let deps = nub $ map depName (buildDepends pkgDesc)
-                   ++ setupDependencies pkgDesc
-  in filter excludedPkgs (delete self deps)
-
-setupDependencies :: PackageDescription  -- ^pkg description
-                  -> [String]         -- ^depends
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,24,0)
-setupDependencies pkgDesc =
-  maybe [] (map depName . setupDepends) (setupBuildInfo pkgDesc)
-#else
-setupDependencies _pkgDesc = []
-#endif
-
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,22,0)
-#else
-unPackageName :: PackageName -> String
-unPackageName (PackageName n) = n
-#endif
-
-depName :: Dependency -> String
-depName (Dependency  n _) = unPackageName n
+excludedPkgs :: PackageName -> Bool
+excludedPkgs =
+  flip notElem $ map mkPackageName ["ghc-prim", "integer-gmp"]
 
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-exeDepName :: LegacyExeDependency -> String
-exeDepName (LegacyExeDependency n _) = n
+data LibPkgType = LibBase | LibDevel | LibProf | LibDoc | LibStatic
 
-pkgcfgDepName :: PkgconfigDependency -> String
-pkgcfgDepName (PkgconfigDependency n _) = unPkgconfigName n
-#else
-exeDepName :: Dependency -> String
-exeDepName = depName
+instance Show LibPkgType where
+  show LibBase = ""
+  show LibDevel = "devel"
+  show LibProf = "prof"
+  show LibDoc = "doc"
+  show LibStatic = "static"
 
-pkgcfgDepName :: Dependency -> String
-pkgcfgDepName = depName
-#endif
+pkgSuffix :: LibPkgType -> String
+pkgSuffix lpt =
+  let rep = show lpt in
+  if null rep then "" else '-' : rep
 
-showDep :: String -> String
-showDep p = "ghc-" ++ p ++ "-devel"
+ghcDep :: LibPkgType -> PackageName -> String
+ghcDep lt p = "ghc-" ++ unPackageName p ++ pkgSuffix lt
 
 dependencies :: PackageDescription  -- ^pkg description
-                -> IO ([String], [String], [String], [String])
-                -- ^depends, tools, c-libs, pkgcfg
-dependencies pkgDesc = do
-    let self = packageName $ package pkgDesc
-        deps = buildDependencies pkgDesc self
+                -> ([PackageName], [PackageName], [String], [String], [String])
+                -- ^depends, setup, tools, c-libs, pkgcfg
+dependencies pkgDesc =
+    let self = pkgName $ package pkgDesc
+        deps = filter excludedPkgs $ buildDependencies pkgDesc
+        setup = filter excludedPkgs $ setupDependencies pkgDesc
         buildinfo = allBuildInfo pkgDesc
         tools =  nub $ map exeDepName (concatMap buildTools buildinfo)
         pkgcfgs = nub $ map pkgcfgDepName $ concatMap pkgconfigDepends buildinfo
         clibs = nub $ concatMap extraLibs buildinfo
-    return (deps, delete self tools, clibs, pkgcfgs)
+        stdcpp = "stdc++"
+        cpp = ["gcc-c++" | stdcpp `elem` clibs]
+    in (deps, setup \\ (mkPackageName "Cabal" : deps), delete (unPackageName self) tools ++ cpp, clibs \\ ["m", stdcpp], pkgcfgs)
 
 data QueryBackend = Rpm | Repoquery deriving Eq
 
@@ -149,7 +105,7 @@
   if libInst
     then rpmqueryFile Rpm lib_path
     else do
-    putStrLn $ "Running repoquery on" +-+ "lib" ++ lib
+    putStrLn $ "Running repoquery for" +-+ lib_path
     rpmqueryFile Repoquery lib_path
 
 -- use repoquery or rpm -q to query which package provides file
@@ -170,49 +126,56 @@
       warning $ "More than one package seems to provide" +-+ file ++ ": " +-+ unwords pkgs
       return Nothing
 
-warning :: String -> IO ()
-warning s = hPutStrLn stderr $ "Warning:" +-+ s
-
-packageDependencies :: Bool   -- ^strict mode: True means abort on unknown dependencies
-                -> PackageDescription  -- ^pkg description
-                -> IO ([String], [String], [String], [String])
-                -- ^depends, tools, c-libs, pkgcfg
-packageDependencies strict pkgDesc = do
-    (deps, tools', clibs', pkgcfgs) <- dependencies pkgDesc
-    let excludedTools n = n `notElem` ["ghc", "hsc2hs", "perl"]
+packageDependencies :: PackageDescription  -- ^pkg description
+                -> IO ([PackageName], [PackageName], [String], [String], [String])
+                -- ^depends, setup, tools, c-libs, pkgcfg
+packageDependencies pkgDesc = do
+    let (deps, setup, tools', clibs', pkgcfgs) = dependencies pkgDesc
+        excludedTools n = n `notElem` ["ghc", "hsc2hs", "perl"]
         mapTools "cabal" = "cabal-install"
         mapTools "gtk2hsC2hs" = "gtk2hs-buildtools"
         mapTools "gtk2hsHookGenerator" = "gtk2hs-buildtools"
         mapTools "gtk2hsTypeGen" = "gtk2hs-buildtools"
+        mapTools "hspec-discover" = "ghc-hspec-discover-devel"
         mapTools tool = tool
         tools = filter excludedTools $ nub $ map mapTools tools'
     clibsWithErrors <- mapM resolveLib clibs'
+
     when (any isNothing clibsWithErrors) $
-      if strict
-      then fail "cannot resolve all clib dependencies"
-      else putStrLn "Warning: could not resolve all clib dependencies"
+      warning "could not resolve all clib dependencies"
     let clibs = catMaybes clibsWithErrors
     let showPkgCfg p = "pkgconfig(" ++ p ++ ")"
-    return (map showDep deps, tools, nub clibs, map showPkgCfg pkgcfgs)
+    return (deps, setup, tools, nub clibs, map showPkgCfg pkgcfgs)
 
-testsuiteDependencies :: PackageDescription  -- ^pkg description
-                -> String           -- ^self
-                -> [String]         -- ^depends
-testsuiteDependencies pkgDesc self =
-  map showDep . delete self . filter excludedPkgs . nub . map depName $ concatMap (targetBuildDepends . testBuildInfo) (testSuites pkgDesc)
+testsuiteDependencies' :: PackageDescription -> [PackageName]
+testsuiteDependencies' =
+  filter excludedPkgs . testsuiteDependencies
 
 missingPackages :: PackageDescription -> IO [String]
 missingPackages pkgDesc = do
-  (deps, tools, clibs, pkgcfgs) <- packageDependencies False pkgDesc
+  (deps, setup, tools, clibs, pkgcfgs) <- packageDependencies pkgDesc
   pcpkgs <- mapM derefPkg pkgcfgs
-  filterM notSrcOrInst $ deps ++ ["ghc-Cabal-devel", "ghc-rpm-macros"] ++ tools ++ clibs ++ pcpkgs
-  where
-    notSrcOrInst :: String -> IO Bool
-    notSrcOrInst pkg = do
-      src <- doesDirectoryExist (".." </> removeSuffix "-devel" pkg)
-      if src then return False
-        else notInstalled pkg
+  filterM notSrcOrInst $ nub $ map (ghcDep LibDevel) (deps ++ setup) ++ ["ghc-Cabal-devel", "ghc-rpm-macros"] ++ tools ++ clibs ++ pcpkgs
 
+missingLibraries :: PackageDescription -> IO [PackageName]
+missingLibraries pkgDesc = do
+  (deps, setup, _, _, _) <- packageDependencies pkgDesc
+  bdeps <- filterM (notSrcOrInst . ghcDep LibProf) deps
+  sdeps <- filterM (notSrcOrInst . ghcDep LibDevel) $ (mkPackageName "Cabal" : setup) \\ deps
+  return $ bdeps ++ sdeps
+
+missingOtherPkgs :: PackageDescription -> IO [String]
+missingOtherPkgs pkgDesc = do
+  (_, _, tools, clibs, pkgcfgs) <- packageDependencies pkgDesc
+  pcpkgs <- mapM derefPkg pkgcfgs
+  filterM notSrcOrInst $ nub $ ["ghc-rpm-macros"] ++ tools ++ clibs ++ pcpkgs
+
+notSrcOrInst :: String -> IO Bool
+notSrcOrInst pkg = do
+  src <- doesDirectoryExist (".." </> removeLibSuffix pkg)
+  if src then return False
+    else notInstalled pkg
+
 notInstalled :: String -> IO Bool
 notInstalled dep =
   not <$> cmdBool "rpm" ["-q", "--quiet", "--whatprovides", shellQuote dep]
@@ -232,21 +195,27 @@
     singleLine "" = ""
     singleLine s = (head . lines) s
 
-subPackages :: Maybe FilePath -> PackageDescription -> IO [String]
+subPackages :: Maybe FilePath -> PackageDescription -> IO [PackageName]
 subPackages mspec pkgDesc = do
-  develSubpkgs <- filter ("-devel" `isSuffixOf`) <$> maybe (return []) (rpmspec [] (Just "%{name}")) mspec
-  let self = packageName $ package pkgDesc
-  return $ delete (showDep self) develSubpkgs
+  develSubpkgs <- map stripPkgDevel . filter ("-devel" `isSuffixOf`) <$> maybe (return []) (rpmspec [] (Just "%{name}")) mspec
+  let self = pkgName $ package pkgDesc
+  return $ delete self $ map mkPackageName develSubpkgs
 
-pkgInstallMissing :: RpmFlags -> PackageData -> IO ()
-pkgInstallMissing flags pkgdata = do
+pkgInstallMissing :: Flags -> Stream -> Maybe Package -> IO [String]
+pkgInstallMissing flags stream mpkg = do
+  pkgdata <- prepare flags stream mpkg True
+  pkgInstallMissing' pkgdata
+
+pkgInstallMissing' :: PackageData -> IO [String]
+pkgInstallMissing' pkgdata = do
   let pkgDesc = packageDesc pkgdata
       mspec = specFilename pkgdata
-  missing <- missingPackages pkgDesc
-  unless (null missing) $ do
+  missing <- missingLibraries pkgDesc
+  if null missing then return []
+    else do
     subpkgs <- subPackages mspec pkgDesc
-    let pkgs = missing \\ subpkgs
-    pkgconfdir <- fromJust . lookup "Global Package DB" . read <$> cmd (ghcCmd flags) ["--info"]
+    let pkgs = map (ghcDep LibProf) $ missing \\ subpkgs
+    pkgconfdir <- fromJust . lookup "Global Package DB" . read <$> cmd "ghc" ["--info"]
     putStrLn $ "Running repoquery" +-+ unwords pkgs
     repopkgs <- filter (/= "") <$> mapM (repoqueryPackageConf pkgconfdir) pkgs
     let missing' = pkgs \\ repopkgs
@@ -258,7 +227,8 @@
       mapM_ putStrLn repopkgs
       -- fedora <- rpmEval "%fedora"
       -- let nogpgcheck = ["--nogpgcheck" | fedora `elem` []]
-      rpmInstall $ map showPkg repopkgs
+      rpmInstall True $ map showPkg repopkgs
+    return missing'
         where
           showPkg :: String -> String
           showPkg p = if '(' `elem` p then show p else p
@@ -269,9 +239,6 @@
         then pkgconfd </> stripPkgDevel pkg ++ "-[0-9]*.conf"
         else pkg in
     repoquery ["--qf", "%{name}"] key
-
-ghcCmd :: RpmFlags -> FilePath
-ghcCmd flags = maybe "ghc" show $ rpmCompilerId flags
 
 isGhcDevelPkg :: String -> Bool
 isGhcDevelPkg p =
diff --git a/src/Distro.hs b/src/Distro.hs
deleted file mode 100644
--- a/src/Distro.hs
+++ /dev/null
@@ -1,48 +0,0 @@
--- |
--- Module      :  Distro
--- Copyright   :  (C) 2016, 2018  Jens Petersen
---
--- Maintainer  :  Jens Petersen <petersen@fedoraproject.org>
---
--- Types and utility functions to represent different RPM-based distributions.
-
--- 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 3 of the License, or
--- (at your option) any later version.
-
-module Distro (defaultRelease,
-               detectDistro,
-               parseDistroName,
-               readDistroName,
-               Distro(..)) where
-
-import SysCmd (rpmEval, rpmMacroDefined)
-import Data.Maybe (fromMaybe, isNothing)
-import Data.Char (toLower)
-
-data Distro = Fedora | RHEL5 | SUSE deriving (Show, Eq)
-
-detectDistro :: IO Distro
-detectDistro = do
-  suse <- rpmMacroDefined "suse_version"
-  if suse then return SUSE
-    else do
-    dist <- rpmEval "%{?dist}"
-    -- RHEL5 does not have macros.dist
-    return $ if isNothing dist || dist == Just ".el5" then RHEL5 else Fedora
-
-parseDistroName :: String -> Maybe Distro
-parseDistroName x = lookup (map toLower x) known
-  where
-    known = [ ("suse", SUSE)
-            , ("fedora", Fedora)
-            , ("rhel5", RHEL5)
-            ]
-
-readDistroName :: String -> Distro
-readDistroName s = fromMaybe (error $ "unrecognized distribution name " ++ show s) (parseDistroName s)
-
-defaultRelease :: Distro -> String
-defaultRelease distro =
-    if distro == SUSE then "0" else "1"
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -16,6 +16,16 @@
 
 module Main where
 
+import Control.Applicative ((<|>)
+#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
+#else
+                         , (<$>), (<*>)
+#endif
+                           )
+import Distribution.Verbosity (normal, silent)
+import System.IO (BufferMode(LineBuffering), hSetBuffering, stdout)
+
+import Commands.BuildDep (builddep)
 import Commands.Depends (depends, Depends (..))
 import Commands.Diff (diff)
 import Commands.Install (install)
@@ -24,33 +34,73 @@
 import Commands.Spec (createSpecFile_)
 import Commands.Update (update)
 
-import Options (parseArgs)
-import PackageUtils (prepare, RpmStage (..))
+import PackageUtils (RpmStage (..))
+import Paths_cabal_rpm       (version)
+import Types
 
-import System.Environment (getArgs)
-import System.IO (BufferMode(LineBuffering), hSetBuffering, stdout)
+import SimpleCmdArgs --(simpleCmdArgs, subcommands)
 
 main :: IO ()
 main = do
   hSetBuffering stdout LineBuffering
-  (opts, cmd, mpkg) <- getArgs >>= parseArgs
-  pkgdata <- prepare opts mpkg True
-  case cmd of
-    "spec"        -> createSpecFile_ pkgdata opts Nothing
-    "srpm"        -> rpmBuild_ pkgdata opts Source
-    "prep"        -> rpmBuild_ pkgdata opts Prep
-    "local"       -> rpmBuild_ pkgdata opts Binary
-    "build"       -> rpmBuild_ pkgdata opts Binary
-    "builddep"    -> rpmBuild_ pkgdata opts BuildDep
-    "diff"        -> diff pkgdata opts mpkg
-    "install"     -> install pkgdata opts
-    "depends"     -> depends pkgdata Depends
-    "refresh"     -> refresh pkgdata opts
-    "requires"    -> depends pkgdata Requires
-    "missingdeps" -> depends pkgdata Missing
-    "update"      -> update pkgdata opts mpkg
-    "rpm"         -> do
-      putStrLn "* Warning the 'rpm' command has been renamed to 'build':"
-      putStrLn "* this alias may be removed in a future release."
-      rpmBuild_ pkgdata opts Binary
-    c -> error $ "Unknown cmd: " ++ c
+  simpleCmdArgs (Just version) "Cabal-rpm tool"
+    "RPM package tool for Haskell Stackage/Hackage packages" $
+    subcommands
+    [ Subcommand "spec" "Generate a spec file" $
+      createSpecFile_ Nothing <$> quietOpt <*> flags <*> force <*> pkgtype <*> subpackage <*> stream <*> packageArg
+    , Subcommand "srpm" "Generate an srpm" $
+      rpmBuild_ Source <$> flags <*> pkgtype <*> subpackage <*> stream <*> packageArg
+    , Subcommand "prep" "Unpack source" $
+      rpmBuild_ Prep <$> flags <*> pkgtype <*> subpackage <*> stream <*> packageArg
+    , Subcommand "local" "Build rpm package locally" $
+      rpmBuild_ Binary <$> flags <*> pkgtype <*> subpackage <*> stream <*> packageArg
+    , Subcommand "build" "Alias for 'local' - builds rpm locally" $
+      rpmBuild_ Binary <$> flags <*> pkgtype <*> subpackage <*> stream <*> packageArg
+    , Subcommand "builddep" "Install build dependencies with dnf" $
+      builddep <$> flags <*> stream <*> packageArg
+    , Subcommand "install" "Build and install recursively" $
+      install <$> flags <*> pkgtype <*> subpackage <*> stream <*> packageArg
+    -- should be (optional versionArg) not pkgver
+    , Subcommand "diff" "Diff with pristine generated spec file" $
+      diff <$> flags <*> pkgtype <*> stream <*> packageArg
+    , Subcommand "depends" "List Haskell dependencies" $
+      depends Depends <$> flags <*> stream <*> packageArg
+    , Subcommand "requires" "List buildrequires for package" $
+      depends Requires <$> flags <*> stream <*> packageArg
+    , Subcommand "missingdeps" "List dependencies not available" $
+      depends Missing <$> flags <*> stream <*> packageArg
+    , Subcommand "refresh" "Refresh spec file to lastest packaging" $
+      refresh <$> dryrun <*> pkgtype <*> stream <*> packageArg
+    , Subcommand "update" "Update package to latest version" $
+      update <$> stream <*> optional versionArg
+    ]
+  where
+    packageArg :: Parser (Maybe Package)
+    packageArg = optional (strArg "PKG[VER]")
+
+    stream :: Parser Stream
+    stream = optionalWith auto 's' "stream" "STREAM" "Stackage stream or Hackage" (LTS "13")
+
+    flags :: Parser Flags
+    flags = optionalWith auto 'f' "flag" "[(String,Bool)]" "Set or disable Cabal flags" []
+
+    force :: Parser Bool
+    force = switchWith 'F' "force" "Force overwriting existing of any .spec file"
+
+    dryrun = switchWith 'n' "dry-run" "Just show patch"
+
+    -- quietOpt :: Parser Verbosity
+    quietOpt = flagWith normal silent 'q' "quiet" "Silence Cabal"
+
+    pkgtype :: Parser PackageType
+    pkgtype =
+      flagWith' StandalonePkg 't' "standalone" "Create a standalone package that uses cabal-install to build and install" <|>
+      flagWith DefaultPkg BinaryPkg 'b' "binary" "Make the base package name to be the Haskell package name"
+
+    subpackage :: Parser Bool
+    subpackage = switchWith 'S' "subpackage" "Subpackage missing Haskell dependencies"
+
+    -- FIXME: use Version
+    versionArg :: Parser String
+    versionArg = strArg "VERSION"
+
diff --git a/src/Options.hs b/src/Options.hs
deleted file mode 100644
--- a/src/Options.hs
+++ /dev/null
@@ -1,189 +0,0 @@
--- |
--- Module      :  Options
--- Copyright   :  (C) 2007-2008  Bryan O'Sullivan
---                (C) 2012-2018  Jens Petersen
---
--- Maintainer  :  Jens Petersen <petersen@fedoraproject.org>
--- Stability   :  alpha
--- Portability :  portable
---
--- Explanation: Command line option processing for building RPM
--- packages.
-
--- 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 3 of the License, or
--- (at your option) any later version.
-
-module Options (
-      RpmFlags(..)
-    , parseArgs
-    , quiet
-    ) where
-
-import Control.Monad (unless, when)
-import Data.Char     (toLower)
-import Data.Maybe    (listToMaybe, fromMaybe)
-import Data.Version  (showVersion)
-
-import Distribution.Compiler           (CompilerId)
-import Distribution.Text               (simpleParse)
-import Distribution.PackageDescription (
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-                                       FlagName, mkFlagName
-#else
-                                       FlagName (..)
-#endif
-                                       )
-import Distribution.ReadE              (readEOrFail)
-import Distribution.Verbosity          (Verbosity, flagToVerbosity, normal,
-                                        silent)
-
-import System.Console.GetOpt (ArgDescr (..), ArgOrder (..), OptDescr (..),
-                              getOpt', usageInfo)
-import System.Environment    (getProgName)
-import System.Exit           (ExitCode (..), exitSuccess, exitWith)
-import System.IO             (Handle, hPutStrLn, stderr, stdout)
-
-import Distro                (Distro(..), readDistroName)
-import Paths_cabal_rpm       (version)
-import SimpleCmd             ((+-+))
-
-data RpmFlags = RpmFlags
-    { rpmConfigurationsFlags :: [(FlagName, Bool)]
-    , rpmForce               :: Bool
-    , rpmHelp                :: Bool
-    , rpmBinary              :: Bool
-    , rpmStandalone          :: Bool
-    , rpmStrict              :: Bool
-    , rpmSubpackage          :: Bool
-    , rpmMissing             :: Bool
-    , rpmStream              :: String
-    , rpmRelease             :: Maybe String
-    , rpmCompilerId          :: Maybe CompilerId
-    , rpmDistribution        :: Maybe Distro
-    , rpmVerbosity           :: Verbosity
-    , rpmVersion             :: Bool
-    }
-    deriving (Eq, Show)
-
-emptyRpmFlags :: RpmFlags
-emptyRpmFlags = RpmFlags
-    { rpmConfigurationsFlags = []
-    , rpmForce = False
-    , rpmHelp = False
-    , rpmBinary = False
-    , rpmStandalone = False
-    , rpmStrict = False
-    , rpmSubpackage = False
-    , rpmMissing = False
-    , rpmStream = defaultStream
-    , rpmRelease = Nothing
-    , rpmCompilerId = Nothing
-    , rpmDistribution = Nothing
-    , rpmVerbosity = normal
-    , rpmVersion = False
-    }
-
-defaultStream :: String
-defaultStream = "lts-12"
-
-quiet :: RpmFlags
-quiet = emptyRpmFlags {rpmVerbosity = silent}
-
-options :: [OptDescr (RpmFlags -> RpmFlags)]
-options =
-  [ Option "h?" ["help"] (NoArg (\x -> x { rpmHelp = True }))
-    "Show this help text"
-  , Option "b" ["binary"] (NoArg (\x -> x { rpmBinary = True }))
-    "Force Haskell package name to be base package name"
-  , Option "" ["force"] (NoArg (\x -> x { rpmForce = True }))
-    "Overwrite existing spec file."
-  , Option "s" ["stream"] (ReqArg (\s x -> x { rpmStream = s }) "STREAM") $
-    "Stackage stream (default '" ++ defaultStream ++ "') or 'hackage' used to get package version."
-  , Option "" ["missing"] (NoArg (\x -> x { rpmMissing = True }))
-    "Comment out missing BuildRequires packages."
-  , Option "" ["standalone"] (NoArg (\x -> x { rpmStandalone = True }))
-    "Create a standalone package that uses cabal-install to build and install."
-  , Option "" ["strict"] (NoArg (\x -> x { rpmStrict = True }))
-    "Fail rather than produce an incomplete spec file."
-  , Option "" ["subpackage"] (NoArg (\x -> x { rpmSubpackage = True }))
-    "Subpackage missing dependencies."
-  , Option "V" ["version"] (NoArg (\x -> x { rpmVersion = True }))
-    "Show version number"
-  , Option "f" ["flags"] (ReqArg (\flags x -> x { rpmConfigurationsFlags = rpmConfigurationsFlags x ++ flagList flags }) "FLAGS")
-    "Set given flags in Cabal conditionals"
-  , Option "" ["release"] (ReqArg (\rel x -> x { rpmRelease = Just rel }) "RELEASE")
-    "Override the default package release"
-  , Option "" ["compiler"] (ReqArg (\cid x -> x { rpmCompilerId = Just (parseCompilerId cid) }) "COMPILER-ID")
-    "Finalize Cabal files targetting the given compiler version"
-  , Option "" ["distro"] (ReqArg (\did x -> x { rpmDistribution = Just (readDistroName did) }) "DISTRO")
-    "Choose the distribution generated spec files will target"
-  , Option "v" ["verbose"] (ReqArg (\verb x -> x { rpmVerbosity = readEOrFail flagToVerbosity verb }) "n")
-    "Change build verbosity"
-  ]
-
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-#else
-mkFlagName :: String -> FlagName
-mkFlagName = FlagName
-#endif
-
--- Lifted from Distribution.Simple.Setup, since it's not exported.
-flagList :: String -> [(FlagName, Bool)]
-flagList = map tagWithValue . words
-  where tagWithValue ('-':name) = (mkFlagName (map toLower name), False)
-        tagWithValue name       = (mkFlagName (map toLower name), True)
-
-printHelp :: Handle -> IO ()
-printHelp h = do
-  progName <- getProgName
-  let info = "Usage: " ++ progName ++ " [OPTION]... COMMAND [PATH|PKG|PKG-VERSION]\n"
-             ++ "\n"
-             ++ "PATH can be a .spec file, .cabal file, or pkg dir.\n"
-             ++ "\n"
-             ++ "Commands:\n"
-             ++ "  spec\t\t- generate a spec file\n"
-             ++ "  srpm\t\t- generate a src rpm file\n"
-             ++ "  prep\t\t- unpack source\n"
-             ++ "  local\t\t- build rpm package locally\n"
-             ++ "  builddep\t- install dependencies\n"
-             ++ "  install\t- install packages recursively\n"
-             ++ "  depends\t- list Cabal depends\n"
-             ++ "  requires\t- list package buildrequires\n"
-             ++ "  missingdeps\t- list missing buildrequires\n"
-             ++ "  diff\t\t- diff current spec file\n"
-             ++ "  update\t- update spec file package to latest version\n"
-             ++ "  refresh\t- refresh spec file to current cabal-rpm\n"
-             ++ "\n"
-             ++ "Options:"
-  hPutStrLn h (usageInfo info options)
-
-parseCompilerId :: String -> CompilerId
-parseCompilerId x = fromMaybe err (simpleParse x)
-  where err = error (show x ++ " is not a valid compiler id")
-
-parseArgs :: [String] -> IO (RpmFlags, String, Maybe String)
-parseArgs args = do
-  let (os, args', unknown, errs) = getOpt' Permute options args
-      opts = foldl (flip ($)) emptyRpmFlags os
-  when (rpmHelp opts) $ do
-    printHelp stdout
-    exitSuccess
-  when (rpmVersion opts) $ do
-    putStrLn $ showVersion version
-    exitSuccess
-  unless (null errs) $
-    error $ unlines errs
-  unless (null unknown) $
-    error $ "Unrecognised options:" +-+ unwords unknown
-  when (null args') $ do
-    printHelp stderr
-    exitWith (ExitFailure 1)
-  when (head args' `notElem` ["builddep", "depends", "diff", "install", "missingdeps", "prep", "requires", "spec", "srpm", "build", "local", "rpm", "update", "refresh"]) $ do
-    hPutStrLn stderr $ "Unknown command:" +-+ head args'
-    printHelp stderr
-    exitWith (ExitFailure 1)
-  when (length args' > 2) $
-    error $ "Too many arguments:" +-+ unwords args'
-  return (opts, head args', listToMaybe $ tail args')
diff --git a/src/PackageUtils.hs b/src/PackageUtils.hs
--- a/src/PackageUtils.hs
+++ b/src/PackageUtils.hs
@@ -28,25 +28,30 @@
   packageVersion,
   patchSpec,
   prepare,
-  prettyShow,
   readVersion,
+  removeLibSuffix,
   removePrefix,
   removeSuffix,
   repoquery,
   rpmbuild,
   rpmInstall,
   RpmStage (..),
-  stripPkgDevel
+  stripPkgDevel,
+  unPackageName
   ) where
 
 import FileUtils (filesWithExtension, fileWithExtension,
-                  getDirectoryContents_, mktempdir, withTempDirectory)
-import Options (RpmFlags (..))
-import SimpleCmd (cmd, cmd_, cmdIgnoreErr, cmdLines, grep_, sudo,
-                  (+-+))
+                  getDirectoryContents_, mktempdir, withCurrentDirectory,
+                  withTempDirectory)
+import SimpleCabal (finalPackageDescription, licenseFiles, mkPackageName,
+                    PackageName, packageName, packageVersion,
+                    tryFindPackageDesc, unPackageName)
+import SimpleCmd (cmd, cmd_, cmdIgnoreErr, cmdLines, grep_, removePrefix,
+                  removeSuffix, sudo, sudo_, (+-+))
 import SimpleCmd.Git (isGitDir, grepGitConfig)
-import SysCmd (die, optionalProgram, requireProgram, rpmEval)
+import SysCmd (optionalProgram, requireProgram, rpmEval)
 import Stackage (latestStackage)
+import Types
 
 #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
 #else
@@ -55,8 +60,8 @@
 import Control.Monad    (filterM, unless, when)
 
 import Data.Char (isDigit, toLower)
-import Data.List (groupBy, isPrefixOf, isSuffixOf, nub, sort, stripPrefix)
-import Data.Maybe (isNothing, fromJust, fromMaybe)
+import Data.List (groupBy, isPrefixOf, isSuffixOf, nub, sort)
+import Data.Maybe (isNothing, isJust, fromJust)
 import Data.Time.Clock (diffUTCTime, getCurrentTime)
 import Data.Version (
 #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))
@@ -67,72 +72,10 @@
 #endif
                     )
 
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,2,0)
-import Distribution.Pretty (prettyShow)
-#else
-import qualified Distribution.Version (showVersion, Version)
-#endif
-#else
-import qualified Data.Version (showVersion)
-#endif
-
-import Distribution.Compiler
-import Distribution.Package  (PackageIdentifier (..),
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,22,0)
-                                        unPackageName
-#else
-                                        PackageName (..)
-#endif
-                                       )
 import Distribution.PackageDescription (PackageDescription (..),
                                         hasExes, hasLibs
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,2,0)
-                                       , mkFlagAssignment
-#endif
                                        )
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-import Distribution.PackageDescription.Configuration (finalizePD)
-import Distribution.Types.ComponentRequestedSpec (defaultComponentRequestedSpec)
-#else
-import Distribution.PackageDescription.Configuration (finalizePackageDescription)
-#endif
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,2,0)
-import Distribution.PackageDescription.Parsec (readGenericPackageDescription)
-#elif defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-import Distribution.PackageDescription.Parse (readGenericPackageDescription)
-#else
-import Distribution.PackageDescription.Parse (readPackageDescription)
-#endif
 
-import Distribution.Simple.Compiler (
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,22,0)
-    compilerInfo
-#else
-    Compiler (..)
-#endif
-    )
-import Distribution.Simple.Configure (
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,18,0)
-    configCompilerEx
-#else
-    configCompiler
-#endif
-    )
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-import Distribution.Simple.Program   (defaultProgramDb)
-#else
-import Distribution.Simple.Program   (defaultProgramConfiguration)
-#endif
-import Distribution.Simple.Utils (
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,20,0)
-    tryFindPackageDesc
-#else
-    findPackageDesc
-#endif
-    )
-import Distribution.System (Platform (..), buildArch, buildOS)
-
 import System.Directory (copyFile, createDirectoryIfMissing, doesDirectoryExist,
                          doesFileExist, getCurrentDirectory,
                          getDirectoryContents, getModificationTime,
@@ -145,17 +88,6 @@
 import System.Posix.Files (accessTime, fileMode, getFileStatus,
                            modificationTime, setFileMode)
 
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,2,0)
-#else
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-prettyShow :: Distribution.Version.Version -> String
-prettyShow = Distribution.Version.showVersion
-#else
-prettyShow :: Version -> String
-prettyShow = Data.Version.showVersion
-#endif
-#endif
-
 stripVersion :: String -> String
 stripVersion n | '-' `notElem` n = n
 stripVersion nv = if hasVer then reverse emaN else nv
@@ -163,69 +95,18 @@
     (reV, '-':emaN) = break (== '-') $ reverse nv
     hasVer = all (\c -> isDigit c || c == '.') reV
 
-simplePackageDescription :: FilePath -> RpmFlags
+simplePackageDescription :: Flags -> FilePath
                          -> IO (PackageDescription, [FilePath], [FilePath])
-simplePackageDescription cabalfile opts = do
-  final <- finalPackageDescription cabalfile opts
+simplePackageDescription flags cabalfile = do
+  final <- finalPackageDescription flags cabalfile
   (docs, licensefiles) <- findDocsLicenses (dropFileName cabalfile) final
   return (final, docs, licensefiles)
 
-finalPackageDescription :: FilePath -> RpmFlags
-                          -> IO PackageDescription
-finalPackageDescription cabalfile opts = do
-  let verbose = rpmVerbosity opts
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-#else
-  let readGenericPackageDescription = readPackageDescription
-      defaultProgramDb = defaultProgramConfiguration
-#endif
-
-  genPkgDesc <- readGenericPackageDescription verbose cabalfile
-  compiler <- case rpmCompilerId opts of
-                Just cid -> return
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,22,0)
-                              (unknownCompilerInfo cid NoAbiTag)
-#else
-                              cid
-#endif
-                Nothing -> do
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,18,0)
-                              (compiler, _, _) <- configCompilerEx
-#else
-                              (compiler, _) <- configCompiler
-#endif
-                                (Just GHC) Nothing Nothing defaultProgramDb verbose
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,22,0)
-                              return (compilerInfo compiler)
-#else
-                              return (compilerId compiler)
-#endif
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,2,0)
-#else
-  let mkFlagAssignment = id
-#endif
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
-  let finalizePackageDescription flags = finalizePD flags defaultComponentRequestedSpec
-#endif
-  let final =
-        finalizePackageDescription (mkFlagAssignment $ rpmConfigurationsFlags opts)
-        (const True) (Platform buildArch buildOS)
-        compiler
-        [] genPkgDesc
-  case final of
-    Left e -> die $ "finalize failed: " ++ show e
-    Right res -> return $ fst res
-
 findDocsLicenses :: FilePath -> PackageDescription -> IO ([FilePath], [FilePath])
 findDocsLicenses dir pkgDesc = do
   contents <- getDirectoryContents dir
   let docs = sort $ filter unlikely $ filter (likely docNames) contents
-  let licenses = sort $ nub $
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,20,0)
-        licenseFiles pkgDesc
-#else
-        [licenseFile pkgDesc | licenseFile pkgDesc /= ""]
-#endif
+  let licenses = sort $ nub $ licenseFiles pkgDesc
         ++ filter (likely licenseNames) contents
       docfiles = if null licenses then docs else filter (`notElem` licenses) docs
   return (docfiles, licenses)
@@ -237,12 +118,6 @@
         unlikely name = not $ any (`isSuffixOf` name) ["~", ".cabal"]
 
 
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,20,0)
-#else
-tryFindPackageDesc :: FilePath -> IO FilePath
-tryFindPackageDesc = findPackageDesc
-#endif
-
 cabalFromSpec :: FilePath -> Bool -> IO FilePath
 cabalFromSpec specFile revise = do
   -- no rpmspec command in RHEL 5 and 6
@@ -253,8 +128,10 @@
     then do
     specTime <- modificationTime <$> getFileStatus specFile
     dirTime <- accessTime <$> getFileStatus namever
-    when (specTime > dirTime) $
+    when (specTime > dirTime) $ do
       rpmbuild Prep specFile
+      dExists' <- doesDirectoryExist namever
+      when dExists' $ cmd_ "touch" [namever]
     else
     rpmbuild Prep specFile
   tryFindPackageDesc namever
@@ -350,7 +227,7 @@
   where
     (rev, '-':eman) = break (== '-') $ reverse nv
 
-data RpmStage = Binary | Source | Prep | BuildDep deriving Eq
+data RpmStage = Binary | Source | Prep deriving Eq
 
 rpmbuild :: RpmStage -> FilePath -> IO ()
 rpmbuild mode spec = do
@@ -358,7 +235,6 @@
         Binary -> "a"
         Source -> "s"
         Prep -> "p"
-        BuildDep -> "_"
   cwd <- getCurrentDirectory
   gitDir <- isGitDir "."
   let rpmdirs_override =
@@ -369,18 +245,15 @@
     rpmdirs_override ++
     [spec]
 
-removePrefix :: String -> String-> String
-removePrefix pref str = fromMaybe str (stripPrefix pref str)
-
-removeSuffix :: String -> String -> String
-removeSuffix suffix orig =
-  fromMaybe orig $ stripSuffix suffix orig
-  where
-    stripSuffix sf str = reverse <$> stripPrefix (reverse sf) (reverse str)
-
 stripPkgDevel :: String -> String
 stripPkgDevel = removeSuffix "-devel" . removePrefix "ghc-"
 
+removeLibSuffix :: String -> String
+removeLibSuffix p | "-devel" `isSuffixOf` p = removeSuffix "-devel" p
+                  | "-prof" `isSuffixOf` p = removeSuffix "-prof" p
+                  | "-static" `isSuffixOf` p = removeSuffix "-static" p
+                  | otherwise = p
+
 cabalUpdate :: IO ()
 cabalUpdate = do
   home <- getEnv "HOME"
@@ -395,7 +268,8 @@
       if haveFile then do
         ts <- getModificationTime tsfile
         t <- getCurrentTime
-        when (diffUTCTime t ts > 600) $ cmd_ "cabal" ["update"]
+        -- less than 3 hours
+        when (diffUTCTime t ts > 10000) $ cmd_ "cabal" ["update"]
         return True
         else
         return False
@@ -415,8 +289,12 @@
   isdir <- doesDirectoryExist pkgver
   if isdir
     then do
-    pth <- tryFindPackageDesc pkgver
-    return (pth, Nothing)
+    let (n,_) = nameVersion pkgver
+    mcabal <- withCurrentDirectory pkgver $ checkForCabalFile (Just n)
+    if isJust mcabal then do
+      pth <- tryFindPackageDesc pkgver
+      return (pth, Nothing)
+      else error $ "could not find" +-+ n <.> "cabal"
     else do
     cwd <- getCurrentDirectory
     tmpdir <- mktempdir
@@ -426,16 +304,17 @@
     setCurrentDirectory cwd
     return (tmpdir </> pth, Just tmpdir)
 
-latestPackage :: String -> String -> IO String
-latestPackage "hackage" pkg = latestHackage pkg
-latestPackage str pkg = do
-  stk <- latestStackage str pkg
+latestPackage :: Stream -> PackageName -> IO String
+latestPackage Hackage pkg = latestHackage pkg
+latestPackage stream pkg = do
+  stk <- latestStackage stream pkg
   case stk of
     Just pv -> return pv
     Nothing -> latestHackage pkg
 
-latestHackage :: String -> IO String
-latestHackage pkg = do
+latestHackage :: PackageName -> IO String
+latestHackage pkgname = do
+  let pkg = unPackageName pkgname
   contains_pkg <- cabal "list" ["-v0", pkg]
   let top = dropWhile (/= "*" +-+ pkg) contains_pkg
   if null top
@@ -450,33 +329,21 @@
       putStrLn $ res +-+ "in Hackage"
       return res
 
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,22,0)
-#else
-unPackageName :: PackageName -> String
-unPackageName (PackageName n) = n
-#endif
-
-packageName :: PackageIdentifier -> String
-packageName = unPackageName . pkgName
-
-packageVersion :: PackageIdentifier -> String
-packageVersion = prettyShow . pkgVersion
-
 getPkgName :: Maybe FilePath -> PackageDescription -> Bool -> IO (String, Bool)
 getPkgName (Just spec) pkgDesc binary = do
-  let name = packageName $ package pkgDesc
+  let name = unPackageName . packageName $ package pkgDesc
       pkgname = takeBaseName spec
       hasLib = hasLibs pkgDesc
   return $ if name == pkgname || binary then (name, hasLib) else (pkgname, False)
 getPkgName Nothing pkgDesc binary = do
-  let name = packageName $ package pkgDesc
+  let name = unPackageName . packageName $ package pkgDesc
       hasExec = hasExes pkgDesc
       hasLib = hasLibs pkgDesc
   return $ if binary || hasExec && not hasLib then (name, hasLib) else ("ghc-" ++ name, False)
 
 checkForSpecFile :: Maybe String -> IO (Maybe FilePath)
 checkForSpecFile mpkg = do
-  allSpecs <- allSpecfiles
+  allSpecs <- filesWithExtension "." ".spec"
   -- emacs makes ".#*.spec" tmp files
   let predicate = maybe ((/= '.') . head) (\ pkg -> (`elem` [pkg <.> "spec", "ghc-" ++ pkg <.> "spec"])) mpkg
       specs = filter predicate allSpecs
@@ -487,11 +354,18 @@
     [] -> return Nothing
     _ -> error "More than one spec file found!"
 
-allSpecfiles :: IO [FilePath]
-allSpecfiles = filesWithExtension "." ".spec"
+checkForCabalFile :: Maybe Package -> IO (Maybe FilePath)
+checkForCabalFile mpkg = do
+  allCabals <- filesWithExtension "." ".cabal"
+  let predicate = maybe (const True) (\ pkg -> (== pkg <.> "cabal")) mpkg
+      cabals = filter predicate allCabals
+  case cabals of
+    [one] -> return $ Just one
+    [] -> return Nothing
+    _ -> error "More than one cabal file found!"
 
-checkForCabalFile :: String -> IO (Maybe FilePath)
-checkForCabalFile pkgmver = do
+checkForPkgCabalFile :: String -> IO (Maybe FilePath)
+checkForPkgCabalFile pkgmver = do
   let pkg = stripVersion pkgmver
       cabalfile = pkg <.> "cabal"
   pkgcabal <- doesFileExist cabalfile
@@ -519,41 +393,48 @@
 
 -- Nothing implies existing packaging in cwd
 -- Something implies either new packaging or some existing spec file in dir
-prepare :: RpmFlags -> Maybe String -> Bool -> IO PackageData
-prepare flags mpkgver revise = do
+prepare :: Flags -> Stream -> Maybe Package -> Bool -> IO PackageData
+prepare flags stream mpkgver revise = do
   let mpkg = stripVersion <$> mpkgver
   mspec <- checkForSpecFile mpkg
   case mspec of
     Just spec -> do
       cabalfile <- cabalFromSpec spec revise
-      (pkgDesc, docs, licenses) <- simplePackageDescription cabalfile flags
+      (pkgDesc, docs, licenses) <- simplePackageDescription flags cabalfile
       return $ PackageData mspec docs licenses pkgDesc
     Nothing ->
       case mpkgver of
         Nothing -> do
-          cwd <- getCurrentDirectory
-          prepare flags (Just $ takeFileName cwd) revise
+          mcabal <- checkForCabalFile mpkg
+          case mcabal of
+            Just cabalfile -> do
+              (pkgDesc, docs, licenses) <- simplePackageDescription flags cabalfile
+              return $ PackageData Nothing docs licenses pkgDesc
+            Nothing -> do
+              cwd <- getCurrentDirectory
+              prepare flags stream (Just $ takeFileName cwd) revise
         Just pkgmver -> do
-          mcabal <- checkForCabalFile pkgmver
+          mcabal <- checkForPkgCabalFile pkgmver
           case mcabal of
             Just cabalfile -> do
-              (pkgDesc, docs, licenses) <- simplePackageDescription cabalfile flags
+              (pkgDesc, docs, licenses) <- simplePackageDescription flags cabalfile
               return $ PackageData Nothing docs licenses pkgDesc
             Nothing -> do
               pkgver <- if stripVersion pkgmver == pkgmver
-                        then latestPackage (rpmStream flags) pkgmver
+                        then latestPackage stream (mkPackageName pkgmver)
                         else return pkgmver
               (cabalfile, mtmp) <- tryUnpack pkgver revise
-              (pkgDesc, docs, licenses) <- simplePackageDescription cabalfile flags
+              (pkgDesc, docs, licenses) <- simplePackageDescription flags cabalfile
               maybe (return ()) removeDirectoryRecursive mtmp
               return $ PackageData Nothing docs licenses pkgDesc
 
-patchSpec :: Maybe FilePath -> FilePath -> FilePath -> IO ()
-patchSpec mdir oldspec newspec = do
+patchSpec :: Bool -> Maybe FilePath -> FilePath -> FilePath -> IO ()
+patchSpec dryrun mdir oldspec newspec = do
   diff <- cmdIgnoreErr "diff" ["-u2", "-I", "- spec file generated by cabal-rpm", "-I", "Fedora Haskell SIG <haskell@lists.fedoraproject.org>", oldspec, newspec] "" >>= cmdIgnoreErr "sed" ["-e", "s/.cblrpm//"]
   putStrLn diff
-  out <- cmdIgnoreErr "patch" opts diff
-  putStrLn out
+  unless dryrun $ do
+    out <- cmdIgnoreErr "patch" opts diff
+    putStrLn out
   where
     opts = ["--fuzz=1"] ++ ["-p1" | '/' `elem` newspec] ++ maybe [] (\ d -> ["-d", d]) mdir
 
@@ -568,15 +449,15 @@
 repoquery args key = do
   havednf <- optionalProgram "dnf"
   let (prog, subcmd) = if havednf then ("dnf", ["repoquery", "-q"]) else ("repoquery", [])
-  cmd prog (subcmd ++ args ++ [key])
+  sudo prog (subcmd ++ args ++ [key])
 
-rpmInstall :: [String] -> IO ()
-rpmInstall [] = return ()
-rpmInstall rpms = do
+rpmInstall :: Bool -> [String] -> IO ()
+rpmInstall _ [] = return ()
+rpmInstall yes rpms = do
   pkginstaller <- packageManager
   let (inst, arg) = if pkginstaller == "dnf" then ("dnf", "install") else ("yum", "localinstall")
   tty <- hIsTerminalDevice stdout
-  sudo inst $ ["-y" | not tty] ++ [arg] ++ rpms
+  sudo_ inst $ ["-y" | yes || not tty] ++ [arg] ++ rpms
 
 editSpecField :: String -> String -> FilePath -> IO ()
 editSpecField field new spec =
diff --git a/src/Stackage.hs b/src/Stackage.hs
--- a/src/Stackage.hs
+++ b/src/Stackage.hs
@@ -20,12 +20,12 @@
   ) where
 
 
-import Control.Monad (when, unless)
+import Control.Monad (when)
 import Data.Maybe (isJust, fromJust)
-import Data.List (isPrefixOf)
 
 #ifdef HTTPS
 import qualified Data.ByteString.Char8 as B
+import Data.List (isPrefixOf)
 import Data.Maybe (mapMaybe)
 import Network.HTTP.Client
 import Network.HTTP.Client.TLS
@@ -39,13 +39,15 @@
 import SimpleCmd ((+-+), cmdMaybe)
 import SysCmd (optionalProgram)
 #endif
+import SimpleCabal (PackageName, unPackageName)
+import Types
 
-stackageList :: String -> String -> IO (Maybe String)
+stackageList :: Stream -> PackageName -> IO (Maybe String)
 stackageList stream pkg = do
 #ifdef HTTPS
   mgr <- newManager tlsManagerSettings
-  let pkgurl = topurl ++ stream ++ "/package/"
-  req <- parseRequest $ pkgurl ++ pkg
+  let pkgurl = topurl ++ (show stream) ++ "/package/"
+  req <- parseRequest $ pkgurl ++ unPackageName pkg
   hist <- responseOpenHistory req mgr
   let redirs = mapMaybe (lookup "Location" . responseHeaders . snd) $ hrRedirects hist
   if null redirs
@@ -63,17 +65,15 @@
   haveStackage <- optionalProgram "stackage"
   if haveStackage
     then
-    fmap ((pkg ++ "-") ++) <$> cmdMaybe "stackage" ["package", stream, pkg]
+    fmap ((unPackageName pkg ++ "-") ++) <$> cmdMaybe "stackage" ["package", show stream, unPackageName pkg]
     else do
     putStrLn "'cabal install stackage-query' to check against Stackage LTS"
     return Nothing
 #endif
 
-latestStackage :: String -> String -> IO (Maybe String)
+latestStackage :: Stream -> PackageName -> IO (Maybe String)
 latestStackage stream pkg = do
-  unless (any (`isPrefixOf` stream) ["nightly", "lts"]) $
-    putStrLn $ "Unknown Stackage stream:" +-+ stream
   mpkg <- stackageList stream pkg
   when (isJust mpkg) $
-    putStrLn $ fromJust mpkg +-+ "in Stackage" +-+ stream
+    putStrLn $ fromJust mpkg +-+ "in Stackage" +-+ show stream
   return mpkg
diff --git a/src/SysCmd.hs b/src/SysCmd.hs
--- a/src/SysCmd.hs
+++ b/src/SysCmd.hs
@@ -29,12 +29,8 @@
 import Control.Monad    (void, when)
 import Data.Maybe       (isJust, isNothing)
 
-#if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(1,18,0)
 #if defined(MIN_VERSION_Cabal) && MIN_VERSION_Cabal(2,0,0)
 import Distribution.Simple.Utils (dieNoVerbosity)
-#else
-import Distribution.Simple.Utils (die)
-#endif
 #else
 import Distribution.Simple.Utils (die)
 #endif
diff --git a/src/Types.hs b/src/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Types.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE CPP #-}
+
+-- |
+-- Module      :  Types
+-- Copyright   :  (C) 2019  Jens Petersen
+--
+-- Maintainer  :  Jens Petersen <petersen@fedoraproject.org>
+--
+-- Explanation: types for cabal-rpm
+
+-- 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 3 of the License, or
+-- (at your option) any later version.
+
+module Types (
+  Flags, -- flagList,
+  Package,
+  PackageType(..),
+  Stream(..),
+  Verbose(..)
+  ) where
+
+import Data.Char (isDigit {--, toLower--})
+import Data.List
+import Data.Maybe (fromMaybe)
+#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,11,0))
+#else
+import Data.Semigroup ((<>))
+#endif
+import SimpleCabal (FlagName {--, mkFlagName--})
+
+type Package = String
+
+data Verbose = Quiet | Verbose
+  deriving Eq
+
+type Flags = [(FlagName, Bool)]
+
+-- -- lifted from Distribution.Simple.Setup, since it's not exported.
+-- flagList :: String -> Flags
+-- flagList = map tagWithValue . words
+--   where tagWithValue ('-':name) = (mkFlagName (map toLower name), False)
+--         tagWithValue name       = (mkFlagName (map toLower name), True)
+
+data Stream = LatestNightly | LatestLTS | LTS String | Nightly String | Hackage
+
+instance Show Stream where
+  show LatestNightly = "nightly"
+  show LatestLTS = "lts"
+  show (Nightly date) = "nightly-" <> date
+  show (LTS ver) = "lts-" <> ver
+  show Hackage = "hackage"
+
+instance Read Stream where
+  readsPrec _ "hackage" = [(Hackage,"")]
+  readsPrec _ "nightly" = [(LatestNightly,"")]
+  readsPrec _ "lts" = [(LatestLTS,"")]
+  readsPrec _ input | "nightly-" `isPrefixOf` input =
+    let (date,rest) = span (\ c -> isDigit c || c == '-') $ removePrefix "nightly-" input in
+       [(Nightly date,rest)]
+  readsPrec _ input | "lts-" `isPrefixOf` input =
+    let (ver,rest) = span (\ c -> isDigit c || c == '.') $ removePrefix "lts-" input in
+      [(LTS ver,rest)]
+  readsPrec _ _ = []
+
+removePrefix :: String -> String-> String
+removePrefix pref orig = fromMaybe orig (stripPrefix pref orig)
+
+data PackageType = DefaultPkg | BinaryPkg | StandalonePkg | SpecFile FilePath
+  deriving Eq
