packunused 0.1.0.1 → 0.1.1.0
raw patch · 3 files changed
+99/−59 lines, 3 filesdep ~Cabaldep ~basedep ~haskell-src-exts
Dependency ranges changed: Cabal, base, haskell-src-exts
Files
- changelog.md +11/−0
- packunused.cabal +9/−6
- packunused.hs +79/−53
+ changelog.md view
@@ -0,0 +1,11 @@+# 0.1.1.0++ - Update to support `Cabal-1.18`/`Cabal-1.20`, GHC 7.8.1+, and `haskell-src-exts-1.15`++# 0.1.0.1++ - Add support for `haskell-src-exts-1.14.0`++# 0.1.0.0++ - Initial release
packunused.cabal view
@@ -1,15 +1,16 @@ name: packunused-version: 0.1.0.1+version: 0.1.1.0 synopsis: Tool for detecting redundant Cabal package dependencies homepage: https://github.com/hvr/packunused+bug-reports: https://github.com/hvr/packunused/issues license: BSD3 license-file: LICENSE-author: Herbert Valerio Riedel <hvr@gnu.org>+author: Herbert Valerio Riedel maintainer: Herbert Valerio Riedel <hvr@gnu.org>+copyright: © 2014 Herbert Valerio Riedel category: Distribution build-type: Simple cabal-version: >=1.10-tested-with: GHC ==7.6.3, GHC ==7.6.2, GHC ==7.6.1, GHC ==7.4.2, GHC ==7.4.1 description: This simple CLI tool allows to find out which of the packages listed as @build-depends@ in a Cabal package description file are redundant.@@ -55,6 +56,8 @@ > - criterion-0.6.2.0-9dd4d764629a47662168743b2dfda9bc > +extra-source-files: changelog.md+ source-repository head type: git location: https://github.com/hvr/packunused.git@@ -65,9 +68,9 @@ other-extensions: CPP, DeriveDataTypeable, RecordWildCards ghc-options: -Wall -fwarn-tabs -fno-warn-unused-do-bind build-depends:- base >=4.5 && <4.7,- Cabal >=1.14 && <1.17,+ base >=4.5 && <4.8,+ Cabal >=1.14 && <1.21, cmdargs ==0.10.*, directory >=1.1 && <1.3, filepath ==1.3.*,- haskell-src-exts >=1.13 && <1.15+ haskell-src-exts >=1.13 && <1.16
packunused.hs view
@@ -5,9 +5,10 @@ import Control.Monad import Data.List import Data.Maybe-import Data.Version (showVersion)+import Data.Version (Version(Version), showVersion) import Distribution.InstalledPackageInfo (exposedModules, installedPackageId) import Distribution.ModuleName (ModuleName)+import Distribution.Simple.Compiler import qualified Distribution.ModuleName as MN import Distribution.Package (InstalledPackageId(..)) import qualified Distribution.PackageDescription as PD@@ -18,17 +19,12 @@ import Distribution.Text (display) import qualified Language.Haskell.Exts as H import System.Console.CmdArgs.Implicit-import System.Directory (getModificationTime, getDirectoryContents, doesFileExist)+import System.Directory (getModificationTime, getDirectoryContents, doesDirectoryExist, doesFileExist) import System.Exit (exitFailure) import System.FilePath ((</>)) import Paths_packunused (version) -#if !MIN_VERSION_Cabal(1,16,0)-componentBuildInfo :: Component -> PD.BuildInfo-componentBuildInfo = foldComponent PD.libBuildInfo PD.buildInfo PD.testBuildInfo PD.benchmarkBuildInfo-#endif- -- |CLI Options data Opts = Opts { ignoreEmptyImports :: Bool@@ -37,8 +33,8 @@ opts :: Opts opts = Opts- { ignoreEmptyImports = def &= explicit &= name "ignore-empty-imports"- , ignoreMainModule = def &= explicit &= name "ignore-main-module"+ { ignoreEmptyImports = def &= name "ignore-empty-imports" &= explicit+ , ignoreMainModule = def &= name "ignore-main-module" &= explicit } &= program "packunused" &= summary ("packunused " ++ showVersion version ++ " (using Cabal "++ showVersion cabalVersion ++ ")")@@ -50,7 +46,7 @@ , "In order to use this package you should set up the package as follows, before executing 'packunused':" , "" , " cabal clean"- , " rm *.imports"+ , " rm *.imports # (only needed for GHC<7.8)" , " cabal configure -O0 --disable-library-profiling" , " cabal build --ghc-option=-ddump-minimal-imports" , " packunused"@@ -75,7 +71,6 @@ lbiMTime <- getModificationTime (localBuildInfoFile distPref) lbi <- getPersistBuildConfig distPref - let cbo = compBuildOrder lbi -- minory sanity checking case pkgDescrFile lbi of@@ -84,53 +79,49 @@ res <- checkPersistBuildConfigOutdated distPref pkgDescFile when res $ putStrLn "*WARNING* outdated config-data -- please re-configure" + let cbo = compBuildOrder lbi+ pkg = localPkgDescr lbi+ ipkgs = installedPkgs lbi++ importsInOutDir <- case compilerId (compiler lbi) of+ CompilerId GHC (Version v _) | v >= [7,8] -> return True+ CompilerId GHC _ -> return False+ CompilerId _ _ -> putStrLn "*WARNING* non-GHC compiler detected" >> return False+ putHeading "detected package components" - when (isJust $ libraryConfig lbi) $+ when (isJust $ PD.library pkg) $ putStrLn $ " - library" ++ [ '*' | CLibName `notElem` cbo ]- unless (null $ executableConfigs lbi) $+ unless (null $ PD.executables pkg) $ putStrLn $ " - executable(s): " ++ unwords [ n ++ [ '*' | CExeName n `notElem` cbo ]- | (n,_) <- executableConfigs lbi ]- unless (null $ testSuiteConfigs lbi) $+ | PD.Executable { exeName = n } <- PD.executables pkg ]+ unless (null $ PD.testSuites pkg) $ putStrLn $ " - testsuite(s): " ++ unwords [ n ++ [ '*' | CTestName n `notElem` cbo ]- | (n,_) <- testSuiteConfigs lbi ]- unless (null $ benchmarkConfigs lbi) $+ | PD.TestSuite { testName = n } <- PD.testSuites pkg ]+ unless (null $ PD.benchmarks pkg) $ putStrLn $ " - benchmark(s): " ++ unwords [ n ++ [ '*' | CBenchName n `notElem` cbo ]- | (n,_) <- benchmarkConfigs lbi ]+ | PD.Benchmark { benchmarkName = n} <- PD.benchmarks pkg ]+ putStrLn "" putStrLn "(component names suffixed with '*' are not configured to be built)" putStrLn "" - let ipkgs = installedPkgs lbi-- files <- filterM doesFileExist =<< liftM (sort . filter (isSuffixOf ".imports")) (getDirectoryContents ".")-- when (null files) $- fail "no .imports files found -- has 'cabal build' been performed yet? (see also --help)"-- -- .import files generated after lbi- files' <- filterM (liftM (> lbiMTime) . getModificationTime) files-- unless (files' == files) $ do- putStrLn "*WARNING* some possibly outdated .imports were found (please consider removing/rebuilding them):"- forM_ (files \\ files') $ \fn -> putStrLn $ " - " ++ fn- putStrLn ""-- -- when (null files') $- -- fail "no up-to-date .imports files found -- please perform 'cabal build'"-- -- import dependancy graph read in via '.imports' files- mods <- mapM readImports files+ ---------------------------------------------------------------------------- - let multiMain = length cbo > libCount+1- libCount = if CLibName `elem` cbo then 1 else 0+ -- GHC prior to 7.8.1 emitted .imports file in $PWD and therefore would risk overwriting files+ let multiMainIssue = not importsInOutDir && length (filter (/= CLibName) cbo) > 1 -- handle stanzas- withComponentsLBI (localPkgDescr lbi) lbi $ \c clbi -> do+ withAllComponentsInBuildOrder pkg lbi $ \c clbi -> do let (n,n2,cmods) = componentNameAndModules (not ignoreMainModule) c+ outDir = if null n2 then buildDir lbi else buildDir lbi </> n2 </> n2++"-tmp"+ outDir' = if importsInOutDir then outDir else "." - -- imported modules by component- allmods | ignoreEmptyImports = nub [ m | (mn, imps) <- mods+ -- import dependancy graph read in via '.imports' files+ mods <- mapM (readImports outDir') =<< findImportsFiles outDir' lbiMTime++ -- imported modules by component+ let allmods | ignoreEmptyImports = nub [ m | (mn, imps) <- mods , mn `elem` cmods , (m,_:_) <- imps ]@@ -141,9 +132,6 @@ pkgs = componentPackageDeps clbi - mainObj | null n2 = ""- | otherwise = buildDir lbi </> n2 </> n2++"-tmp" </> "Main.o"- ipinfos = [ fromMaybe (error (show ipkgid)) $ lookupInstalledPackageId ipkgs ipkgid | (ipkgid@(InstalledPackageId i), _) <- pkgs , not ("-inplace" `isSuffixOf` i)@@ -165,11 +153,11 @@ forM_ missingMods $ \m -> putStrLn $ " - " ++ display m putStrLn "" - when (not ignoreMainModule && multiMain && not (compIsLib c)) $ do+ when (not ignoreMainModule && multiMainIssue && not (compIsLib c)) $ do putStrLn "*WARNING* multiple non-library components detected"- putStrLn " result may be unreliable if there are multiple non-library components because the 'Main.imports' file gets overwritten. Try"+ putStrLn " result may be unreliable if there are multiple non-library components because the 'Main.imports' file gets overwritten with GHC prior to version 7.8.1, try" putStrLn ""- putStrLn $ " rm "++mainObj++"; cabal build --ghc-option=-ddump-minimal-imports; packunused"+ putStrLn $ " rm "++(outDir </> "Main.h")++"; cabal build --ghc-option=-ddump-minimal-imports; packunused" putStrLn "" putStrLn " to get a more accurate result for this component." putStrLn ""@@ -181,7 +169,7 @@ else do putStrLn "The following package depencencies seem redundant:" putStrLn ""- forM_ unused $ \pkg -> putStrLn $ " - " ++ display pkg+ forM_ unused $ \pkg' -> putStrLn $ " - " ++ display pkg' putStrLn "" return ()@@ -191,6 +179,36 @@ compIsLib CLib {} = True compIsLib _ = False + findImportsFiles outDir lbiMTime = do+ whenM (not `fmap` doesDirectoryExist outDir) $+ fail $"output-dir " ++ show outDir ++ " does not exist; -- has 'cabal build' been performed yet? (see also 'packunused --help')"++ files <- filterM (doesFileExist . (outDir</>)) =<<+ liftM (sort . filter (isSuffixOf ".imports"))+ (getDirectoryContents outDir)++ when (null files) $+ fail $ "no .imports files found in " ++ show outDir ++ " -- has 'cabal build' been performed yet? (see also 'packunused --help')"++ -- .import files generated after lbi+ files' <- filterM (liftM (> lbiMTime) . getModificationTime . (outDir</>)) files++ unless (files' == files) $ do+ putStrLn "*WARNING* some possibly outdated .imports were found (please consider removing/rebuilding them):"+ forM_ (files \\ files') $ \fn -> putStrLn $ " - " ++ fn+ putStrLn ""++ -- when (null files') $+ -- fail "no up-to-date .imports files found -- please perform 'cabal build'"++ return files++#if MIN_VERSION_Cabal(1,18,0)+ compBuildOrder = map fst . allComponentsInBuildOrder+#else+ withAllComponentsInBuildOrder = withComponentsLBI+#endif+ componentNameAndModules :: Bool -> Component -> (String, String, [ModuleName]) componentNameAndModules addMainMod c = (n, n2, m) where@@ -204,6 +222,10 @@ mainModName = MN.fromString "Main" +#if !MIN_VERSION_Cabal(1,16,0)+ componentBuildInfo = foldComponent PD.libBuildInfo PD.buildInfo PD.testBuildInfo PD.benchmarkBuildInfo+#endif+ putHeading :: String -> IO () putHeading s = do putStrLn s@@ -211,14 +233,14 @@ putStrLn "" -- empty symbol list means '()'-readImports :: FilePath -> IO (ModuleName, [(ModuleName, [String])])-readImports fn = do+readImports :: FilePath -> FilePath -> IO (ModuleName, [(ModuleName, [String])])+readImports outDir fn = do unless (".imports" `isSuffixOf` fn) $ fail ("argument "++show fn++" doesn't have .imports extension") let m = MN.fromString $ take (length fn - length ".imports") fn - parseRes <- H.parseFileWithExts exts fn+ parseRes <- H.parseFileWithExts exts (outDir </> fn) case parseRes of (H.ParseOk (H.Module _ _ _ _ _ imps _)) -> do let imps' = [ (MN.fromString mn, extractSpecs (H.importSpecs imp))@@ -238,3 +260,7 @@ #else exts = [ H.MagicHash, H.PackageImports, H.CPP, H.TypeOperators, H.TypeFamilies {- , H.ExplicitNamespaces -} ] #endif+++whenM :: Monad m => m Bool -> m () -> m ()+whenM test action = test >>= \t -> if t then action else return ()