cabal-dependency-licenses (empty) → 0.1.0.0
raw patch · 5 files changed
+193/−0 lines, 5 filesdep +Cabaldep +basedep +containerssetup-changed
Dependencies added: Cabal, base, containers, directory, filepath
Files
- CHANGELOG +2/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- cabal-dependency-licenses.cabal +29/−0
- src/Main.hs +130/−0
+ CHANGELOG view
@@ -0,0 +1,2 @@+- 0.1.0.0+ * Initial release
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Jasper Van der Jeugt <m@jaspervdj.be>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Jasper Van der Jeugt <m@jaspervdj.be> nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cabal-dependency-licenses.cabal view
@@ -0,0 +1,29 @@+Name: cabal-dependency-licenses+Version: 0.1.0.0+Synopsis: Compose a list of a project's dependencies with their licenses++Description:+ Compose a list of a project's dependencies with their licenses++License: BSD3+License-file: LICENSE+Author: Jasper Van der Jeugt <m@jaspervdj.be>+Maintainer: Jasper Van der Jeugt <m@jaspervdj.be>+Copyright: 2014 Jasper Van der Jeugt+Category: Distribution+Build-type: Simple+Extra-source-files: CHANGELOG+Cabal-version: >= 1.10++Executable cabal-dependency-licenses+ Hs-source-dirs: src+ Main-is: Main.hs+ Default-language: Haskell98+ Ghc-options: -Wall++ Build-depends:+ Cabal >= 1.20 && < 1.21,+ containers >= 0.5 && < 0.6,+ base >= 4 && < 5,+ directory >= 1.2 && < 1.3,+ filepath >= 1.3 && < 1.4
+ src/Main.hs view
@@ -0,0 +1,130 @@+--------------------------------------------------------------------------------+module Main+ ( main+ ) where+++--------------------------------------------------------------------------------+import Control.Monad (forM_, unless)+import Data.List (foldl', sort)+import Data.Maybe (catMaybes)+import Data.Set (Set)+import qualified Data.Set as Set+import Distribution.InstalledPackageInfo (InstalledPackageInfo)+import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo+import qualified Distribution.License as Cabal+import qualified Distribution.Package as Cabal+import qualified Distribution.Simple.Configure as Cabal+import qualified Distribution.Simple.LocalBuildInfo as Cabal+import qualified Distribution.Simple.PackageIndex as Cabal+import qualified Distribution.Text as Cabal+import System.Directory (getDirectoryContents)+import System.Exit (exitFailure)+import System.FilePath (takeExtension)+import System.IO (hPutStrLn, stderr)+++--------------------------------------------------------------------------------+putErrLn :: String -> IO ()+putErrLn = hPutStrLn stderr+++--------------------------------------------------------------------------------+existsCabalFile :: IO Bool+existsCabalFile = do+ contents <- getDirectoryContents "."+ return $ any ((== ".cabal") . takeExtension) contents+++--------------------------------------------------------------------------------+findTransitiveDependencies+ :: Cabal.PackageIndex+ -> Set Cabal.InstalledPackageId+ -> Set Cabal.InstalledPackageId+findTransitiveDependencies pkgIdx set0 = go Set.empty (Set.toList set0)+ where+ go set [] = set+ go set (q : queue)+ | q `Set.member` set = go set queue+ | otherwise =+ case Cabal.lookupInstalledPackageId pkgIdx q of+ Nothing ->+ -- Not found can mean that the package still needs to be+ -- installed (e.g. a component of the target cabal package).+ -- We can ignore those.+ go set queue+ Just ipi ->+ go (Set.insert q set)+ (InstalledPackageInfo.depends ipi ++ queue)+++--------------------------------------------------------------------------------+getDependencyInstalledPackageIds+ :: Cabal.LocalBuildInfo -> Set Cabal.InstalledPackageId+getDependencyInstalledPackageIds lbi =+ findTransitiveDependencies (Cabal.installedPkgs lbi) $+ Set.fromList+ [ installedPackageId+ | (_, componentLbi, _) <- Cabal.componentsConfigs lbi+ , (installedPackageId, _) <- Cabal.componentPackageDeps componentLbi+ ]+++--------------------------------------------------------------------------------+getDependencyInstalledPackageInfos+ :: Cabal.LocalBuildInfo -> [InstalledPackageInfo]+getDependencyInstalledPackageInfos lbi = catMaybes $+ map (Cabal.lookupInstalledPackageId pkgIdx) $+ Set.toList (getDependencyInstalledPackageIds lbi)+ where+ pkgIdx = Cabal.installedPkgs lbi+++--------------------------------------------------------------------------------+groupByLicense+ :: [InstalledPackageInfo]+ -> [(Cabal.License, [InstalledPackageInfo])]+groupByLicense = foldl'+ (\assoc ipi -> insert (InstalledPackageInfo.license ipi) ipi assoc) []+ where+ -- 'Cabal.License' doesn't have an 'Ord' instance so we need to use an+ -- association list instead of 'Map'. The number of licenses probably won't+ -- exceed 100 so I think we're alright.+ insert :: Eq k => k -> v -> [(k, [v])] -> [(k, [v])]+ insert k v [] = [(k, [v])]+ insert k v ((k', vs) : kvs)+ | k == k' = (k, v : vs) : kvs+ | otherwise = (k', vs) : insert k v kvs+++--------------------------------------------------------------------------------+printDependencyLicenseList+ :: [(Cabal.License, [InstalledPackageInfo])]+ -> IO ()+printDependencyLicenseList byLicense =+ forM_ byLicense $ \(license, ipis) -> do+ putStrLn $ "# " ++ Cabal.display license+ putStrLn ""++ let sortedNames = sort $ map getName ipis+ forM_ sortedNames $ \name -> putStrLn $ "- " ++ name+ putStrLn ""+ where+ getName =+ Cabal.display . Cabal.pkgName . InstalledPackageInfo.sourcePackageId+++--------------------------------------------------------------------------------+main :: IO ()+main = do+ -- Check that we're in a directory with a cabal file+ existsCabalFile' <- existsCabalFile+ unless existsCabalFile' $ do+ putErrLn "No cabal file found in the current directory"+ exitFailure++ -- Get info and print dependency license list+ lbi <- Cabal.getPersistBuildConfig "dist"+ printDependencyLicenseList $+ groupByLicense $+ getDependencyInstalledPackageInfos lbi