packages feed

cabal-bounds 0.2.1 → 0.3

raw patch · 22 files changed

+613/−617 lines, 22 filesdep +eitherdep +transformersdep ~lensdep ~tasty

Dependencies added: either, transformers

Dependency ranges changed: lens, tasty

Files

cabal-bounds.cabal view
@@ -1,5 +1,5 @@ name: cabal-bounds-version: 0.2.1+version: 0.3 cabal-version: >=1.9.2 build-type: Simple license: BSD3@@ -164,41 +164,35 @@   library     build-depends: base >=3 && <5, cmdargs >=0.10.5 && <0.11,-                   lens >=4.0.1 && <4.1, strict >=0.3.2 && <0.4,-                   unordered-containers >=0.2.3.3 && <0.3, Cabal >=1.18.0 && <1.19+                   lens >=4.0.1 && <4.2, strict >=0.3.2 && <0.4,+                   unordered-containers >=0.2.3.3 && <0.3,+                   transformers >=0.3.0.0 && <0.4, either >=4.1.1 && <4.2,+                   Cabal >=1.18.0 && <1.19     exposed-modules: CabalBounds.Args CabalBounds.Main                      CabalBounds.VersionComp     exposed: True     buildable: True     cpp-options: -DCABAL-    hs-source-dirs: src+    hs-source-dirs: lib     other-modules: Paths_cabal_bounds CabalBounds.Bound-                   CabalBounds.Targets CabalBounds.Dependencies CabalBounds.Drop+                   CabalBounds.Sections CabalBounds.Dependencies CabalBounds.Drop                    CabalBounds.Update CabalBounds.Lenses     ghc-options: -W   executable cabal-bounds-    build-depends: base >=3 && <5, cmdargs >=0.10.5 && <0.11,-                   lens >=4.0.1 && <4.1, strict >=0.3.2 && <0.4,-                   unordered-containers >=0.2.3.3 && <0.3, Cabal >=1.18.0 && <1.19+    build-depends: base >=3 && <5, cabal-bounds -any     main-is: Main.hs     buildable: True-    cpp-options: -DCABAL-    hs-source-dirs: src-    other-modules: Paths_cabal_bounds CabalBounds.Args-                   CabalBounds.Bound CabalBounds.Targets CabalBounds.Dependencies-                   CabalBounds.Drop CabalBounds.Update CabalBounds.Lenses-                   CabalBounds.VersionComp CabalBounds.Main+    hs-source-dirs: exe     ghc-options: -W   test-suite cabal-bounds-tests-    build-depends: base >=3 && <5, cmdargs >=0.10.5 && <0.11,-                   lens >=4.0.1 && <4.1, strict >=0.3.2 && <0.4,-                   unordered-containers >=0.2.3.3 && <0.3, Cabal >=1.18.0 && <1.19,-                   tasty ==0.7.*, tasty-golden >=2.2.0.2 && <2.3,-                   filepath >=1.3.0.1 && <1.4, cabal-bounds -any+    build-depends: base >=3 && <5, tasty >=0.7 && <0.9,+                   tasty-golden >=2.2.0.2 && <2.3, filepath >=1.3.0.1 && <1.4,+                   cabal-bounds -any     type: exitcode-stdio-1.0-    main-is: tests/Main.hs+    main-is: Main.hs     buildable: True+    hs-source-dirs: tests     ghc-options: -W  
+ exe/Main.hs view
@@ -0,0 +1,15 @@++module Main where++import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr)+import qualified CabalBounds.Args as Args+import CabalBounds.Main (cabalBounds)++main :: IO ()+main = do+  args  <- Args.get+  error <- cabalBounds args+  case error of+       Just err -> hPutStrLn stderr ("cabal-bounds: " ++ err) >> exitFailure+       _        -> exitSuccess
+ lib/CabalBounds/Args.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE DeriveDataTypeable, CPP #-}+{-# OPTIONS_GHC -w #-}++module CabalBounds.Args+   ( Args(..)+   , get+   , outputFile+   , defaultDrop+   , defaultUpdate+   ) where++import System.Console.CmdArgs hiding (ignore)+import CabalBounds.VersionComp (VersionComp(..))++#ifdef CABAL+import Data.Version (showVersion)+import Paths_cabal_bounds (version)+#endif++data Args = Drop { upper      :: Bool+                 , library    :: Bool+                 , executable :: [String]+                 , testSuite  :: [String]+                 , benchmark  :: [String]+                 , only       :: [String]+                 , ignore     :: [String]+                 , output     :: String+                 , cabalFile  :: String+                 }+          | Update { lower           :: Bool+                   , upper           :: Bool+                   , lowerComp       :: Maybe VersionComp+                   , upperComp       :: Maybe VersionComp+                   , library         :: Bool+                   , executable      :: [String]+                   , testSuite       :: [String]+                   , benchmark       :: [String]+                   , only            :: [String]+                   , ignore          :: [String]+                   , output          :: String+                   , cabalFile       :: String+                   , setupConfigFile :: String+                   } +          deriving (Data, Typeable, Show, Eq)+++get :: IO Args+get = cmdArgsRun . cmdArgsMode $ modes [dropArgs, updateArgs]+   &= program "cabal-bounds"+   &= summary summaryInfo+   &= help "A command line program for managing the bounds/versions of the dependencies in a cabal file."+   &= helpArg [explicit, name "help", name "h"]+   &= versionArg [explicit, name "version", name "v", summary versionInfo]+   where+      summaryInfo = ""+++outputFile :: Args -> FilePath+outputFile args+   | null $ output args = cabalFile args+   | otherwise          = output args+++defaultDrop :: Args+defaultDrop = Drop+   { upper           = def+   , library         = def+   , executable      = def+   , testSuite       = def+   , benchmark       = def+   , only            = def+   , ignore          = def+   , output          = def+   , cabalFile       = def+   }+++defaultUpdate :: Args+defaultUpdate = Update+   { lower           = def+   , upper           = def+   , lowerComp       = def+   , upperComp       = def+   , library         = def+   , executable      = def+   , testSuite       = def+   , benchmark       = def+   , only            = def+   , ignore          = def+   , output          = def+   , cabalFile       = def+   , setupConfigFile = def+   }+++dropArgs :: Args+dropArgs = Drop+   { upper           = def &= explicit &= name "upper" &= name "U" &= help "Only the upper bound is dropped, otherwise both - the lower and upper - bounds are dropped."+   , library         = def &= explicit &= name "library" &= name "l" &= help "Only the bounds of the library are modified."+   , executable      = def &= typ "NAME" &= help "Only the bounds of the executable are modified."+   , testSuite       = def &= typ "NAME" &= help "Only the bounds of the test suite are modified."+   , benchmark       = def &= typ "NAME" &= help "Only the bounds of the benchmark are modified."+   , only            = def &= explicit &= typ "DEPENDENCY" &= name "only" &= name "O" &= help "Only the bounds of the dependency are modified."+   , ignore          = def &= explicit &= typ "DEPENDENCY" &= name "ignore" &= name "I" &= help "This dependency is ignored, not modified in any way."+   , output = def &= explicit &= typ "FILE" &= name "output" &= name "o" &= help "Save modified cabal file to file, if empty, the cabal file is modified inplace."+   , cabalFile       = def &= argPos 0 &= typ "CABAL-FILE"+   }+++updateArgs :: Args+updateArgs = Update+   { lower           = def &= explicit &= name "lower" &= name "L" &= help "Only the lower bound is updated. The same as using '--lowercomp=minor'."+   , upper           = def &= explicit &= name "upper" &= name "U" &= help "Only the upper bound is updated. The same as using '--uppercomp=major2'."+   , lowerComp       = def &= explicit &= name "lowercomp" &= help "Only the lower bound is updated with the specified version component. (major1, major2 or minor)" +   , upperComp       = def &= explicit &= name "uppercomp" &= help "Only the upper bound is updated with the specified version component. (major1, major2 or minor)"+   , setupConfigFile = def &= argPos 1 &= typ "SETUP-CONFIG-FILE"+   }+++versionInfo :: String+versionInfo =+#ifdef CABAL+   "cabal-bounds version " ++ showVersion version+#else+   "cabal-bounds version unknown (not built with cabal)"+#endif++
+ lib/CabalBounds/Bound.hs view
@@ -0,0 +1,61 @@+{-# Language PatternGuards #-}++module CabalBounds.Bound+   ( DropBound(..)+   , UpdateBound(..)+   , boundOfDrop+   , boundOfUpdate+   ) where   ++import CabalBounds.Args (Args(Drop, Update))+import qualified CabalBounds.Args as A+import CabalBounds.VersionComp (VersionComp(..), defaultLowerComp, defaultUpperComp)+import Data.Maybe (isJust)++data DropBound = DropUpper+               | DropBoth+               deriving (Show, Eq)++data UpdateBound = UpdateLower VersionComp+                 | UpdateUpper VersionComp+                 | UpdateBoth { lowerComp :: VersionComp, upperComp :: VersionComp }+                 deriving (Show, Eq)+++boundOfDrop :: Args -> DropBound+boundOfDrop Drop {A.upper = upper} = if upper then DropUpper else DropBoth+boundOfDrop _  = error "Expected Drop Args!"+++boundOfUpdate :: Args -> UpdateBound+boundOfUpdate upd@Update {}+   | hasLower && hasUpper+   = UpdateBoth lowerComp upperComp++   | hasLower+   = UpdateLower lowerComp++   | hasUpper+   = UpdateUpper upperComp++   | otherwise+   = UpdateBoth lowerComp upperComp+   where+      lowerComp+         | Just comp <- A.lowerComp upd+         = comp++         | otherwise+         = defaultLowerComp++      upperComp+         | Just comp <- A.upperComp upd+         = comp++         | otherwise+         = defaultUpperComp++      hasLower = A.lower upd || (isJust . A.lowerComp $ upd)+      hasUpper = A.upper upd || (isJust . A.upperComp $ upd)++boundOfUpdate _ = error "Expected Update Args!"
+ lib/CabalBounds/Dependencies.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE PatternGuards, Rank2Types #-}++module CabalBounds.Dependencies+   ( Dependencies(..)+   , dependencies+   , filterDependencies+   ) where++import Control.Lens +import qualified CabalBounds.Args as A+import Distribution.Package (Dependency(..), PackageName(..))++data Dependencies = AllDependencies+                  | OnlyDependencies [String]+                  | IgnoreDependencies [String]+                  deriving (Show, Eq)+++dependencies :: A.Args -> Dependencies+dependencies args+   | ds@(_:_) <- A.only args+   = OnlyDependencies ds++   | ds@(_:_) <- A.ignore args+   = IgnoreDependencies ds++   | otherwise+   = AllDependencies+++filterDependencies :: Dependencies -> Traversal' [Dependency] Dependency+filterDependencies AllDependencies =+   traversed++filterDependencies (OnlyDependencies deps) =+   traversed . filtered (\(Dependency (PackageName pkgName) _) -> any (== pkgName) deps)++filterDependencies (IgnoreDependencies deps) =+   traversed . filtered (\(Dependency (PackageName pkgName) _) -> all (/= pkgName) deps)
+ lib/CabalBounds/Drop.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE PatternGuards #-}++module CabalBounds.Drop+   ( drop+   ) where++import Prelude hiding (drop)+import Control.Lens+import CabalBounds.Bound (DropBound(..))+import CabalBounds.Sections (Sections(..), dependenciesOf)+import CabalBounds.Dependencies (Dependencies, filterDependencies)+import qualified CabalBounds.Lenses as L+import Data.List (foldl')+import Distribution.PackageDescription (GenericPackageDescription)+import Distribution.Package (Dependency(..))+import Distribution.Version (mkVersionIntervals, fromVersionIntervals, asVersionIntervals, UpperBound(..), anyVersion)+++drop :: DropBound -> Sections -> Dependencies -> GenericPackageDescription -> GenericPackageDescription+drop bound AllSections deps pkgDescrp =+   pkgDescrp & L.allDependencies . filterDeps %~ dropFromDep+   where+      filterDeps  = filterDependencies deps+      dropFromDep = dropFromDependency bound+++drop bound (Sections sections) deps pkgDescrp =+   foldl' dropFromSection pkgDescrp sections+   where+      dropFromSection pkgDescrp section =+         pkgDescrp & (dependenciesOf section) . filterDeps %~ dropFromDep++      filterDeps  = filterDependencies deps+      dropFromDep = dropFromDependency bound+++dropFromDependency :: DropBound -> Dependency -> Dependency+dropFromDependency DropUpper (Dependency pkgName versionRange) = Dependency pkgName versionRange'+   where+      versionRange'+         | Just vi <- mkVersionIntervals intervals'+         = fromVersionIntervals vi++         | otherwise+         = versionRange++      intervals' = map (& _2 .~ NoUpperBound) (asVersionIntervals versionRange)++dropFromDependency DropBoth (Dependency pkgName _) = Dependency pkgName anyVersion
+ lib/CabalBounds/Lenses.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE TemplateHaskell, Rank2Types #-}++module CabalBounds.Lenses+   ( vbranch+   , vtags+   , allDependencies+   , dependenciesOfLib+   , dependenciesOfAllExes+   , dependenciesOfExe+   , dependenciesOfAllTests+   , dependenciesOfTest+   , dependenciesOfAllBenchms+   , dependenciesOfBenchm+   ) where++import Distribution.PackageDescription+import Distribution.Package+import Distribution.Version+import Control.Lens+import Data.Data.Lens++makeLensesFor [ ("condLibrary"    , "condLibraryL")+              , ("condExecutables", "condExecutablesL")+              , ("condTestSuites" , "condTestSuitesL")+              , ("condBenchmarks" , "condBenchmarksL")+              ] ''GenericPackageDescription++makeLensesFor [ ("versionBranch", "vbranch")+              , ("versionTags"  , "vtags")+              ] ''Version+++allDependencies :: Traversal' GenericPackageDescription [Dependency]+allDependencies = biplate++dependenciesOfLib :: Traversal' GenericPackageDescription [Dependency]+dependenciesOfLib = condLibraryL . _Just . biplate++dependenciesOfAllExes :: Traversal' GenericPackageDescription [Dependency]+dependenciesOfAllExes = condExecutablesL . traversed . _2 . biplate++dependenciesOfExe :: String -> Traversal' GenericPackageDescription [Dependency]+dependenciesOfExe exe = condExecutablesL . traversed . filtered ((== exe) . fst) . _2 . biplate++dependenciesOfAllTests :: Traversal' GenericPackageDescription [Dependency]+dependenciesOfAllTests = condTestSuitesL . traversed . _2 . biplate++dependenciesOfTest :: String -> Traversal' GenericPackageDescription [Dependency]+dependenciesOfTest test = condTestSuitesL . traversed . filtered ((== test) . fst) . _2 . biplate++dependenciesOfAllBenchms :: Traversal' GenericPackageDescription [Dependency]+dependenciesOfAllBenchms = condBenchmarksL . traversed . _2 . biplate++dependenciesOfBenchm :: String -> Traversal' GenericPackageDescription [Dependency]+dependenciesOfBenchm benchm = condBenchmarksL . traversed . filtered ((== benchm) . fst) . _2 . biplate
+ lib/CabalBounds/Main.hs view
@@ -0,0 +1,58 @@+{-# Language StandaloneDeriving #-}++module CabalBounds.Main+   ( cabalBounds+   ) where++import Distribution.PackageDescription (GenericPackageDescription)+import Distribution.PackageDescription.Parse (parsePackageDescription, ParseResult(..))+import Distribution.PackageDescription.PrettyPrint (showGenericPackageDescription)+import Distribution.Simple.Configure (ConfigStateFileErrorType(..), tryGetConfigStateFile)+import Distribution.Simple.LocalBuildInfo (LocalBuildInfo)+import qualified CabalBounds.Args as A+import qualified CabalBounds.Bound as B+import qualified CabalBounds.Sections as S+import qualified CabalBounds.Dependencies as DP+import qualified CabalBounds.Drop as D+import qualified CabalBounds.Update as U+import qualified System.IO.Strict as SIO+import Control.Applicative ((<$>))+import Control.Monad.Trans.Either (EitherT, runEitherT, bimapEitherT, hoistEither, left, right)+import Control.Monad.IO.Class++type Error = String++cabalBounds :: A.Args -> IO (Maybe Error)+cabalBounds args@A.Drop {} = do+   leftToJust <$> (runEitherT $ do+      pkgDescrp <- packageDescription $ A.cabalFile args+      let pkgDescrp' = D.drop (B.boundOfDrop args) (S.sections args) (DP.dependencies args) pkgDescrp+      liftIO $ writeFile (A.outputFile args) (showGenericPackageDescription pkgDescrp'))++cabalBounds args@A.Update {} = do+   leftToJust <$> (runEitherT $ do+      pkgDescrp <- packageDescription $ A.cabalFile args+      buildInfo <- localBuildInfo $ A.setupConfigFile args+      let pkgDescrp' = U.update (B.boundOfUpdate args) (S.sections args) (DP.dependencies args) pkgDescrp buildInfo+      liftIO $ writeFile (A.outputFile args) (showGenericPackageDescription pkgDescrp'))+++packageDescription :: FilePath -> EitherT Error IO GenericPackageDescription+packageDescription file = do+   contents <- liftIO $ SIO.readFile file+   case parsePackageDescription contents of+        ParseFailed error   -> left $ show error+        ParseOk _ pkgDescrp -> right pkgDescrp+++localBuildInfo :: FilePath -> EitherT Error IO LocalBuildInfo+localBuildInfo file =  do+   binfo <- liftIO $ tryGetConfigStateFile file+   bimapEitherT show id (hoistEither binfo)+++leftToJust :: Either a b -> Maybe a+leftToJust = either Just (const Nothing)+++deriving instance Show ConfigStateFileErrorType
+ lib/CabalBounds/Sections.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE PatternGuards, Rank2Types #-}++module CabalBounds.Sections+   ( Sections(..)+   , Section(..)+   , sections+   , dependenciesOf+   ) where++import Control.Lens+import Distribution.PackageDescription (GenericPackageDescription(..))+import Distribution.Package (Dependency(..))+import CabalBounds.Args (Args)+import qualified CabalBounds.Args as A+import qualified CabalBounds.Lenses as L++data Sections = Sections [Section]+              | AllSections+              deriving (Show, Eq)++-- | A section of the cabal file.+data Section = Library+             | Executable String+             | TestSuite String+             | Benchmark String+             deriving (Show, Eq)++sections :: Args -> Sections+sections args +   | ts@(_:_) <- concat [ if (A.library args) then [Library] else []+                        , map Executable (A.executable args)+                        , map TestSuite (A.testSuite args)+                        , map Benchmark (A.benchmark args)+                        ]+   = Sections ts++   | otherwise+   = AllSections+++dependenciesOf :: Section -> Traversal' GenericPackageDescription [Dependency]+dependenciesOf Library            = L.dependenciesOfLib+dependenciesOf (Executable exe)   = L.dependenciesOfExe exe+dependenciesOf (TestSuite test)   = L.dependenciesOfTest test+dependenciesOf (Benchmark benchm) = L.dependenciesOfBenchm benchm
+ lib/CabalBounds/Update.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE PatternGuards #-}++module CabalBounds.Update+   ( update+   ) where++import qualified Distribution.PackageDescription as D+import qualified Distribution.Package as P+import qualified Distribution.Version as V+import qualified Distribution.Simple.LocalBuildInfo as BI+import qualified Distribution.Simple.PackageIndex as PX+import qualified Distribution.InstalledPackageInfo as PI+import Control.Lens+import Control.Applicative ((<$>))+import CabalBounds.Bound (UpdateBound(..))+import CabalBounds.Sections (Sections(..), dependenciesOf)+import CabalBounds.Dependencies (Dependencies, filterDependencies)+import CabalBounds.VersionComp (VersionComp(..), defaultLowerComp)+import qualified CabalBounds.Lenses as L+import Data.List (sort, foldl')+import qualified Data.HashMap.Strict as HM+import Data.Maybe (fromMaybe, listToMaybe)++type PkgName           = String+type InstalledPackages = HM.HashMap PkgName V.Version+++update :: UpdateBound -> Sections -> Dependencies -> D.GenericPackageDescription -> BI.LocalBuildInfo -> D.GenericPackageDescription+update bound AllSections deps pkgDescrp buildInfo =+   pkgDescrp & L.allDependencies . filterDeps %~ updateDep+   where+      filterDeps = filterDependencies deps+      updateDep  = updateDependency bound (installedPackages buildInfo)++update bound (Sections sections) deps pkgDescrp buildInfo =+   foldl' updateSection pkgDescrp sections+   where+      updateSection pkgDescrp section =+         pkgDescrp & (dependenciesOf section) . filterDeps %~ updateDep++      filterDeps = filterDependencies deps+      updateDep  = updateDependency bound (installedPackages buildInfo)+++updateDependency :: UpdateBound -> InstalledPackages -> P.Dependency -> P.Dependency+updateDependency (UpdateLower comp) instPkgs dep =+   fromMaybe dep $ do+      let pkgName_ = pkgName dep+      version <- HM.lookup pkgName_ instPkgs+      vrange  <- mkVersionRange (comp `compOf` version) Nothing+      return $ mkDependency pkgName_ vrange++updateDependency (UpdateUpper comp) instPkgs dep+   | V.isAnyVersion versionRange_+   = updateDependency (UpdateBoth defaultLowerComp comp) instPkgs dep++   | otherwise+   = fromMaybe dep $ do+        upperVersion                <- HM.lookup pkgName_ instPkgs+        V.LowerBound lowerVersion _ <- fst <$> (listToMaybe $ V.asVersionIntervals versionRange_)+        vrange                      <- mkVersionRange lowerVersion (Just $ nextVersion $ comp `compOf` upperVersion)+        return $ mkDependency pkgName_ vrange+   where+      versionRange_ = versionRange dep+      pkgName_      = pkgName dep++updateDependency (UpdateBoth lowerComp upperComp) instPkgs dep =+   fromMaybe dep $ do+      let pkgName_ = pkgName dep+      version <- HM.lookup pkgName_ instPkgs+      vrange  <- mkVersionRange (lowerComp `compOf` version) (Just $ nextVersion $ upperComp `compOf` version)+      return $ mkDependency pkgName_ vrange+++mkVersionRange :: V.Version -> Maybe V.Version -> Maybe V.VersionRange+mkVersionRange lowerVersion Nothing =+   V.fromVersionIntervals <$> V.mkVersionIntervals [(V.LowerBound lowerVersion V.InclusiveBound, V.NoUpperBound)]++mkVersionRange lowerVersion (Just upperVersion) =+   V.fromVersionIntervals <$> V.mkVersionIntervals [(V.LowerBound lowerVersion V.InclusiveBound,+                                                     V.UpperBound upperVersion V.ExclusiveBound)]+++compOf :: VersionComp -> V.Version -> V.Version+Major1 `compOf` version =+   version & L.vbranch %~ take 1+           & L.vtags   .~ []++Major2 `compOf` version =+   version & L.vbranch %~ take 2+           & L.vtags   .~ []++Minor `compOf` version =+   version & L.vtags .~ []+++nextVersion :: V.Version -> V.Version+nextVersion version =+   version & L.vbranch %~ increaseLastComp+   where+      increaseLastComp = reverse . (& ix 0 %~ (+ 1)) . reverse+++installedPackages :: BI.LocalBuildInfo -> InstalledPackages+installedPackages = HM.fromList+                    . map (\(P.PackageName n, v) -> (n, newestVersion v))+                    . filter ((not . null) . snd)+                    . PX.allPackagesByName . BI.installedPkgs+   where+      newestVersion :: [PI.InstalledPackageInfo] -> V.Version+      newestVersion = last . sort . map (P.pkgVersion . PI.sourcePackageId)+++pkgName :: P.Dependency -> PkgName+pkgName (P.Dependency (P.PackageName name) _) = name+++versionRange :: P.Dependency -> V.VersionRange+versionRange (P.Dependency _ vrange) = vrange+++mkDependency :: PkgName -> V.VersionRange -> P.Dependency+mkDependency name vrange = P.Dependency (P.PackageName name) vrange
+ lib/CabalBounds/VersionComp.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE DeriveDataTypeable #-}++module CabalBounds.VersionComp+   ( VersionComp(..)+   , defaultLowerComp+   , defaultUpperComp+   ) where++import Data.Data (Data(..), Typeable(..))++-- | The component of a version number A.B.C -> Major1.Major2.Minor+data VersionComp = Major1+                 | Major2+                 | Minor+                 deriving (Data, Typeable, Eq, Show)+++defaultLowerComp :: VersionComp+defaultLowerComp = Minor+++defaultUpperComp :: VersionComp+defaultUpperComp = Major2
− src/CabalBounds/Args.hs
@@ -1,128 +0,0 @@-{-# LANGUAGE DeriveDataTypeable, CPP #-}-{-# OPTIONS_GHC -w #-}--module CabalBounds.Args-   ( Args(..)-   , get-   , outputFile-   , defaultDrop-   , defaultUpdate-   ) where--import System.Console.CmdArgs hiding (ignore)-import CabalBounds.VersionComp (VersionComp(..))--#ifdef CABAL-import Data.Version (showVersion)-import Paths_cabal_bounds (version)-#endif--data Args = Drop { upper           :: Bool-                 , library         :: Bool-                 , executable      :: [String]-                 , testSuite       :: [String]-                 , benchmark       :: [String]-                 , only            :: [String]-                 , ignore          :: [String]-                 , outputCabalFile :: String-                 , cabalFile       :: String-                 }-          | Update { lower           :: Bool-                   , upper           :: Bool-                   , lowerComp       :: Maybe VersionComp-                   , upperComp       :: Maybe VersionComp-                   , library         :: Bool-                   , executable      :: [String]-                   , testSuite       :: [String]-                   , benchmark       :: [String]-                   , only            :: [String]-                   , ignore          :: [String]-                   , outputCabalFile :: String-                   , cabalFile       :: String-                   , setupConfigFile :: String-                   } -          deriving (Data, Typeable, Show, Eq)---get :: IO Args-get = cmdArgsRun . cmdArgsMode $ modes [dropArgs, updateArgs]-   &= program "cabal-bounds"-   &= summary summaryInfo-   &= help "A command line program for managing the bounds/versions of the dependencies in a cabal file."-   &= helpArg [explicit, name "help", name "h"]-   &= versionArg [explicit, name "version", name "v", summary versionInfo]-   where-      summaryInfo = ""---outputFile :: Args -> FilePath-outputFile args-   | null $ outputCabalFile args = cabalFile args-   | otherwise                   = outputCabalFile args---defaultDrop :: Args-defaultDrop = Drop-   { upper           = False-   , library         = False-   , executable      = []-   , testSuite       = []-   , benchmark       = []-   , only            = []-   , ignore          = []-   , outputCabalFile = ""-   , cabalFile       = ""-   }---defaultUpdate :: Args-defaultUpdate = Update-   { lower           = False-   , upper           = False-   , lowerComp       = Nothing-   , upperComp       = Nothing-   , library         = False-   , executable      = []-   , testSuite       = []-   , benchmark       = []-   , only            = []-   , ignore          = []-   , outputCabalFile = ""-   , cabalFile       = ""-   , setupConfigFile = ""-   }---dropArgs :: Args-dropArgs = Drop-   { upper           = def &= explicit &= name "upper" &= name "U" &= help "Only the upper bound is dropped, otherwise both - the lower and upper - bounds are dropped."-   , library         = def &= explicit &= name "library" &= name "l" &= help "Only the bounds of the library are modified."-   , executable      = def &= typ "EXECUTABLE" &= help "Only the bounds of the executable are modified."-   , testSuite       = def &= typ "TESTSUITE" &= help "Only the bounds of the test suite are modified."-   , benchmark       = def &= typ "BENCHMARK" &= help "Only the bounds of the benchmark are modified."-   , only            = def &= explicit &= typ "DEPENDENCY" &= name "only" &= name "O" &= help "Only the bounds of the dependency are modified."-   , ignore          = def &= explicit &= typ "DEPENDENCY" &= name "ignore" &= name "I" &= help "This dependency is ignored, not modified in any way."-   , outputCabalFile = def &= explicit &= typ "FILE" &= name "outputCabalFile" &= name "o" &= help "Save modified cabal file to file, if empty, the cabal file is modified inplace."-   , cabalFile       = def &= argPos 0 &= typ "CABAL-FILE"-   }---updateArgs :: Args-updateArgs = Update-   { lower           = def &= explicit &= name "lower" &= name "L" &= help "Only the lower bound is updated. The same as using '--lowercomp=minor'."-   , upper           = def &= explicit &= name "upper" &= name "U" &= help "Only the upper bound is updated. The same as using '--uppercomp=major2'."-   , lowerComp       = def &= explicit &= name "lowercomp" &= help "Only the lower bound is updated with the specified version component. (major1, major2 or minor)" -   , upperComp       = def &= explicit &= name "uppercomp" &= help "Only the upper bound is updated with the specified version component. (major1, major2 or minor)"-   , setupConfigFile = def &= argPos 1 &= typ "SETUP-CONFIG-FILE"-   }---versionInfo :: String-versionInfo =-#ifdef CABAL-   "cabal-bounds version " ++ showVersion version-#else-   "cabal-bounds version unknown (not built with cabal)"-#endif--
− src/CabalBounds/Bound.hs
@@ -1,61 +0,0 @@-{-# Language PatternGuards #-}--module CabalBounds.Bound-   ( DropBound(..)-   , UpdateBound(..)-   , boundOfDrop-   , boundOfUpdate-   ) where   --import CabalBounds.Args (Args(Drop, Update))-import qualified CabalBounds.Args as A-import CabalBounds.VersionComp (VersionComp(..), defaultLowerComp, defaultUpperComp)-import Data.Maybe (isJust)--data DropBound = DropUpper-               | DropBoth-               deriving (Show, Eq)--data UpdateBound = UpdateLower VersionComp-                 | UpdateUpper VersionComp-                 | UpdateBoth { lowerComp :: VersionComp, upperComp :: VersionComp }-                 deriving (Show, Eq)---boundOfDrop :: Args -> DropBound-boundOfDrop Drop {A.upper = upper} = if upper then DropUpper else DropBoth-boundOfDrop _  = error "Expected Drop Args!"---boundOfUpdate :: Args -> UpdateBound-boundOfUpdate upd@Update {}-   | hasLower && hasUpper-   = UpdateBoth lowerComp upperComp--   | hasLower-   = UpdateLower lowerComp--   | hasUpper-   = UpdateUpper upperComp--   | otherwise-   = UpdateBoth lowerComp upperComp-   where-      lowerComp-         | Just comp <- A.lowerComp upd-         = comp--         | otherwise-         = defaultLowerComp--      upperComp-         | Just comp <- A.upperComp upd-         = comp--         | otherwise-         = defaultUpperComp--      hasLower = A.lower upd || (isJust . A.lowerComp $ upd)-      hasUpper = A.upper upd || (isJust . A.upperComp $ upd)--boundOfUpdate _ = error "Expected Update Args!"
− src/CabalBounds/Dependencies.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE PatternGuards, Rank2Types #-}--module CabalBounds.Dependencies-   ( Dependencies(..)-   , dependencies-   , filterDependencies-   ) where--import Control.Lens -import qualified CabalBounds.Args as A-import Distribution.Package (Dependency(..), PackageName(..))--data Dependencies = AllDependencies-                  | OnlyDependencies [String]-                  | IgnoreDependencies [String]-                  deriving (Show, Eq)---dependencies :: A.Args -> Dependencies-dependencies args-   | ds@(_:_) <- A.only args-   = OnlyDependencies ds--   | ds@(_:_) <- A.ignore args-   = IgnoreDependencies ds--   | otherwise-   = AllDependencies---filterDependencies :: Dependencies -> Traversal' [Dependency] Dependency-filterDependencies AllDependencies =-   traversed--filterDependencies (OnlyDependencies deps) =-   traversed . filtered (\(Dependency (PackageName pkgName) _) -> any (== pkgName) deps)--filterDependencies (IgnoreDependencies deps) =-   traversed . filtered (\(Dependency (PackageName pkgName) _) -> all (/= pkgName) deps)
− src/CabalBounds/Drop.hs
@@ -1,49 +0,0 @@-{-# LANGUAGE PatternGuards #-}--module CabalBounds.Drop-   ( drop-   ) where--import Prelude hiding (drop)-import Control.Lens-import CabalBounds.Bound (DropBound(..))-import CabalBounds.Targets (Targets(..), dependenciesOf)-import CabalBounds.Dependencies (Dependencies, filterDependencies)-import qualified CabalBounds.Lenses as L-import Data.List (foldl')-import Distribution.PackageDescription (GenericPackageDescription)-import Distribution.Package (Dependency(..))-import Distribution.Version (mkVersionIntervals, fromVersionIntervals, asVersionIntervals, UpperBound(..), anyVersion)---drop :: DropBound -> Targets -> Dependencies -> GenericPackageDescription -> GenericPackageDescription-drop bound AllTargets deps pkgDescrp =-   pkgDescrp & L.allDependencies . filterDeps %~ dropFromDep-   where-      filterDeps  = filterDependencies deps-      dropFromDep = dropFromDependency bound---drop bound (Targets targets) deps pkgDescrp =-   foldl' dropFromTarget pkgDescrp targets-   where-      dropFromTarget pkgDescrp target =-         pkgDescrp & (dependenciesOf target) . filterDeps %~ dropFromDep--      filterDeps  = filterDependencies deps-      dropFromDep = dropFromDependency bound---dropFromDependency :: DropBound -> Dependency -> Dependency-dropFromDependency DropUpper (Dependency pkgName versionRange) = Dependency pkgName versionRange'-   where-      versionRange'-         | Just vi <- mkVersionIntervals intervals'-         = fromVersionIntervals vi--         | otherwise-         = versionRange--      intervals' = map (& _2 .~ NoUpperBound) (asVersionIntervals versionRange)--dropFromDependency DropBoth (Dependency pkgName _) = Dependency pkgName anyVersion
− src/CabalBounds/Lenses.hs
@@ -1,55 +0,0 @@-{-# LANGUAGE TemplateHaskell, Rank2Types #-}--module CabalBounds.Lenses-   ( vbranch-   , vtags-   , allDependencies-   , dependenciesOfLib-   , dependenciesOfAllExes-   , dependenciesOfExe-   , dependenciesOfAllTests-   , dependenciesOfTest-   , dependenciesOfAllBenchms-   , dependenciesOfBenchm-   ) where--import Distribution.PackageDescription-import Distribution.Package-import Distribution.Version-import Control.Lens-import Data.Data.Lens--makeLensesFor [ ("condLibrary"    , "condLibraryL")-              , ("condExecutables", "condExecutablesL")-              , ("condTestSuites" , "condTestSuitesL")-              , ("condBenchmarks" , "condBenchmarksL")-              ] ''GenericPackageDescription--makeLensesFor [ ("versionBranch", "vbranch")-              , ("versionTags"  , "vtags")-              ] ''Version---allDependencies :: Traversal' GenericPackageDescription [Dependency]-allDependencies = biplate--dependenciesOfLib :: Traversal' GenericPackageDescription [Dependency]-dependenciesOfLib = condLibraryL . _Just . biplate--dependenciesOfAllExes :: Traversal' GenericPackageDescription [Dependency]-dependenciesOfAllExes = condExecutablesL . traversed . _2 . biplate--dependenciesOfExe :: String -> Traversal' GenericPackageDescription [Dependency]-dependenciesOfExe exe = condExecutablesL . traversed . filtered ((== exe) . fst) . _2 . biplate--dependenciesOfAllTests :: Traversal' GenericPackageDescription [Dependency]-dependenciesOfAllTests = condTestSuitesL . traversed . _2 . biplate--dependenciesOfTest :: String -> Traversal' GenericPackageDescription [Dependency]-dependenciesOfTest test = condTestSuitesL . traversed . filtered ((== test) . fst) . _2 . biplate--dependenciesOfAllBenchms :: Traversal' GenericPackageDescription [Dependency]-dependenciesOfAllBenchms = condBenchmarksL . traversed . _2 . biplate--dependenciesOfBenchm :: String -> Traversal' GenericPackageDescription [Dependency]-dependenciesOfBenchm benchm = condBenchmarksL . traversed . filtered ((== benchm) . fst) . _2 . biplate
− src/CabalBounds/Main.hs
@@ -1,57 +0,0 @@-{-# Language StandaloneDeriving #-}--module CabalBounds.Main-   ( cabalBounds-   ) where--import Distribution.PackageDescription (GenericPackageDescription)-import Distribution.PackageDescription.Parse (parsePackageDescription, ParseResult(..))-import Distribution.PackageDescription.PrettyPrint (showGenericPackageDescription)-import Distribution.Simple.Configure (ConfigStateFileErrorType(..), tryGetConfigStateFile)-import Distribution.Simple.LocalBuildInfo (LocalBuildInfo)-import qualified CabalBounds.Args as A-import qualified CabalBounds.Bound as B-import qualified CabalBounds.Targets as T-import qualified CabalBounds.Dependencies as DP-import qualified CabalBounds.Drop as D-import qualified CabalBounds.Update as U-import qualified System.IO.Strict as SIO-import Control.Applicative ((<$>))--type Error = String--cabalBounds :: A.Args -> IO (Maybe Error)-cabalBounds args@A.Drop {} = do-   pkgDescrp <- packageDescription $ A.cabalFile args-   case pkgDescrp of-        Left  error      -> return . Just $ error-        Right pkgDescrp_ -> do-           let pkgDescrp' = D.drop (B.boundOfDrop args) (T.targets args) (DP.dependencies args) pkgDescrp_-           writeFile (A.outputFile args) (showGenericPackageDescription pkgDescrp')-           return Nothing--cabalBounds args@A.Update {} = do-   pkgDescrp <- packageDescription $ A.cabalFile args-   buildInfo <- localBuildInfo $ A.setupConfigFile args-   case (pkgDescrp, buildInfo) of-        (Left error, _) -> return . Just $ error-        (_, Left error) -> return . Just $ error-        (Right pkgDescrp_, Right buildInfo_) -> do-           let pkgDescrp' = U.update (B.boundOfUpdate args) (T.targets args) (DP.dependencies args) pkgDescrp_ buildInfo_-           writeFile (A.outputFile args) (showGenericPackageDescription pkgDescrp')-           return Nothing---packageDescription :: FilePath -> IO (Either Error GenericPackageDescription)-packageDescription file = do-   contents <- SIO.readFile file-   case parsePackageDescription contents of-        ParseFailed error   -> return . Left  $ show error-        ParseOk _ pkgDescrp -> return . Right $ pkgDescrp---localBuildInfo :: FilePath -> IO (Either Error LocalBuildInfo)-localBuildInfo file =-   either (Left . show) Right <$> tryGetConfigStateFile file--deriving instance Show ConfigStateFileErrorType
− src/CabalBounds/Targets.hs
@@ -1,44 +0,0 @@-{-# LANGUAGE PatternGuards, Rank2Types #-}--module CabalBounds.Targets-   ( Targets(..)-   , Target(..)-   , targets-   , dependenciesOf-   ) where--import Control.Lens-import Distribution.PackageDescription (GenericPackageDescription(..))-import Distribution.Package (Dependency(..))-import CabalBounds.Args (Args)-import qualified CabalBounds.Args as A-import qualified CabalBounds.Lenses as L--data Targets = Targets [Target]-             | AllTargets-             deriving (Show, Eq)--data Target = Library-            | Executable String-            | TestSuite String-            | Benchmark String-            deriving (Show, Eq)--targets :: Args -> Targets-targets args -   | ts@(_:_) <- concat [ if (A.library args) then [Library] else []-                        , map Executable (A.executable args)-                        , map TestSuite (A.testSuite args)-                        , map Benchmark (A.benchmark args)-                        ]-   = Targets ts--   | otherwise-   = AllTargets---dependenciesOf :: Target -> Traversal' GenericPackageDescription [Dependency]-dependenciesOf Library            = L.dependenciesOfLib-dependenciesOf (Executable exe)   = L.dependenciesOfExe exe-dependenciesOf (TestSuite test)   = L.dependenciesOfTest test-dependenciesOf (Benchmark benchm) = L.dependenciesOfBenchm benchm
− src/CabalBounds/Update.hs
@@ -1,123 +0,0 @@-{-# LANGUAGE PatternGuards #-}--module CabalBounds.Update-   ( update-   ) where--import qualified Distribution.PackageDescription as D-import qualified Distribution.Package as P-import qualified Distribution.Version as V-import qualified Distribution.Simple.LocalBuildInfo as BI-import qualified Distribution.Simple.PackageIndex as PX-import qualified Distribution.InstalledPackageInfo as PI-import Control.Lens-import Control.Applicative ((<$>))-import CabalBounds.Bound (UpdateBound(..))-import CabalBounds.Targets (Targets(..), dependenciesOf)-import CabalBounds.Dependencies (Dependencies, filterDependencies)-import CabalBounds.VersionComp (VersionComp(..), defaultLowerComp)-import qualified CabalBounds.Lenses as L-import Data.List (sort, foldl')-import qualified Data.HashMap.Strict as HM-import Data.Maybe (fromMaybe, listToMaybe)--type PkgName           = String-type InstalledPackages = HM.HashMap PkgName V.Version---update :: UpdateBound -> Targets -> Dependencies -> D.GenericPackageDescription -> BI.LocalBuildInfo -> D.GenericPackageDescription-update bound AllTargets deps pkgDescrp buildInfo =-   pkgDescrp & L.allDependencies . filterDeps %~ updateDep-   where-      filterDeps = filterDependencies deps-      updateDep  = updateDependency bound (installedPackages buildInfo)--update bound (Targets targets) deps pkgDescrp buildInfo =-   foldl' updateTarget pkgDescrp targets-   where-      updateTarget pkgDescrp target =-         pkgDescrp & (dependenciesOf target) . filterDeps %~ updateDep--      filterDeps = filterDependencies deps-      updateDep  = updateDependency bound (installedPackages buildInfo)---updateDependency :: UpdateBound -> InstalledPackages -> P.Dependency -> P.Dependency-updateDependency (UpdateLower comp) instPkgs dep =-   fromMaybe dep $ do-      let pkgName_ = pkgName dep-      version <- HM.lookup pkgName_ instPkgs-      vrange  <- mkVersionRange (comp `compOf` version) Nothing-      return $ mkDependency pkgName_ vrange--updateDependency (UpdateUpper comp) instPkgs dep-   | V.isAnyVersion versionRange_-   = updateDependency (UpdateBoth defaultLowerComp comp) instPkgs dep--   | otherwise-   = fromMaybe dep $ do-        upperVersion                <- HM.lookup pkgName_ instPkgs-        V.LowerBound lowerVersion _ <- fst <$> (listToMaybe $ V.asVersionIntervals versionRange_)-        vrange                      <- mkVersionRange lowerVersion (Just $ nextVersion $ comp `compOf` upperVersion)-        return $ mkDependency pkgName_ vrange-   where-      versionRange_ = versionRange dep-      pkgName_      = pkgName dep--updateDependency (UpdateBoth lowerComp upperComp) instPkgs dep =-   fromMaybe dep $ do-      let pkgName_ = pkgName dep-      version <- HM.lookup pkgName_ instPkgs-      vrange  <- mkVersionRange (lowerComp `compOf` version) (Just $ nextVersion $ upperComp `compOf` version)-      return $ mkDependency pkgName_ vrange---mkVersionRange :: V.Version -> Maybe V.Version -> Maybe V.VersionRange-mkVersionRange lowerVersion Nothing =-   V.fromVersionIntervals <$> V.mkVersionIntervals [(V.LowerBound lowerVersion V.InclusiveBound, V.NoUpperBound)]--mkVersionRange lowerVersion (Just upperVersion) =-   V.fromVersionIntervals <$> V.mkVersionIntervals [(V.LowerBound lowerVersion V.InclusiveBound,-                                                     V.UpperBound upperVersion V.ExclusiveBound)]---compOf :: VersionComp -> V.Version -> V.Version-Major1 `compOf` version =-   version & L.vbranch %~ take 1-           & L.vtags   .~ []--Major2 `compOf` version =-   version & L.vbranch %~ take 2-           & L.vtags   .~ []--Minor `compOf` version =-   version & L.vtags .~ []---nextVersion :: V.Version -> V.Version-nextVersion version =-   version & L.vbranch %~ increaseLastComp-   where-      increaseLastComp = reverse . (& ix 0 %~ (+ 1)) . reverse---installedPackages :: BI.LocalBuildInfo -> InstalledPackages-installedPackages = HM.fromList-                    . map (\(P.PackageName n, v) -> (n, newestVersion v))-                    . filter ((not . null) . snd)-                    . PX.allPackagesByName . BI.installedPkgs-   where-      newestVersion :: [PI.InstalledPackageInfo] -> V.Version-      newestVersion = last . sort . map (P.pkgVersion . PI.sourcePackageId)---pkgName :: P.Dependency -> PkgName-pkgName (P.Dependency (P.PackageName name) _) = name---versionRange :: P.Dependency -> V.VersionRange-versionRange (P.Dependency _ vrange) = vrange---mkDependency :: PkgName -> V.VersionRange -> P.Dependency-mkDependency name vrange = P.Dependency (P.PackageName name) vrange
− src/CabalBounds/VersionComp.hs
@@ -1,23 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}--module CabalBounds.VersionComp-   ( VersionComp(..)-   , defaultLowerComp-   , defaultUpperComp-   ) where--import Data.Data (Data(..), Typeable(..))---- | The component of a version number A.B.C -> Major1.Major2.Minor-data VersionComp = Major1-                 | Major2-                 | Minor-                 deriving (Data, Typeable, Eq, Show)---defaultLowerComp :: VersionComp-defaultLowerComp = Minor---defaultUpperComp :: VersionComp-defaultUpperComp = Major2
− src/Main.hs
@@ -1,15 +0,0 @@--module Main where--import System.Exit (exitFailure, exitSuccess)-import System.IO (hPutStrLn, stderr)-import qualified CabalBounds.Args as Args-import CabalBounds.Main (cabalBounds)--main :: IO ()-main = do-  args  <- Args.get-  error <- cabalBounds args-  case error of-       Just err -> hPutStrLn stderr ("cabal-bounds: " ++ err) >> exitFailure-       _        -> exitSuccess
tests/Main.hs view
@@ -83,11 +83,11 @@        argsWithFiles =           case args of-              Drop {}   -> args { cabalFile       = inputFile-                                , outputCabalFile = outputFile+              Drop {}   -> args { cabalFile = inputFile+                                , output    = outputFile                                 }               Update {} -> args { cabalFile       = inputFile-                                , outputCabalFile = outputFile+                                , output          = outputFile                                 , setupConfigFile = setupConfigFile                                 }