packages feed

cabal-sort (empty) → 0.0.1

raw patch · 4 files changed

+270/−0 lines, 4 filesdep +Cabaldep +basedep +containerssetup-changed

Dependencies added: Cabal, base, containers, directory, explicit-exception, fgl, filepath, transformers

Files

+ LICENSE view
@@ -0,0 +1,31 @@+Copyright (c) 2010, Henning Thielemann++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.++    * The names of contributors may not 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.lhs view
@@ -0,0 +1,3 @@+#! /usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ cabal-sort.cabal view
@@ -0,0 +1,67 @@+Name:             cabal-sort+Version:          0.0.1+License:          BSD3+License-File:     LICENSE+Author:           Henning Thielemann <haskell@henning-thielemann.de>+Maintainer:       Henning Thielemann <haskell@henning-thielemann.de>+-- Homepage:         http://www.haskell.org/haskellwiki/Cabal+Category:         Distribution+Synopsis:         Topologically sort cabal packages+Description:+  If you have a bunch of packages you may want to compile or recompile,+  then you need an order of compilation that meets the dependencies.+  Given a number of cabal package files,+  this program reads all those files+  and emits them topologically sorted according to their dependencies.+  This way you can compile many packages at once,+  say if a very low-level package has changed.+  .+  For compiling a couple of packages from their local darcs repositories+  in the right order, you may run something like+  .+  > for dir in `find . -name "*.cabal" | fgrep -v _darcs | xargs cabal-sort --info=dir`; do (cd $dir && cabal install); done+  .+  For uploading a set of packages to Hackage in the right order+  you may run+  .+  > for dir in `find . -name "*.cabal" | fgrep -v _darcs | xargs cabal-sort --info=dir`; do (cd $dir && rm dist/*.tar.gz && cabal sdist && cabal upload dist/*.tar.gz); done+  .+  Problem: Given packages A, B, C,+  where C depends on B and B depends on A,+  and you call+  .+  > cabal-sort C.cabal A.cabal+  .+  then the emitted order of packages may be wrong,+  because cabal-sort does not get to know the dependency of C on B.+  Even if the order is correct,+  B.cabal is missing in the output+  and thus the list of cabal files cannot immediately be used+  for a sequence of cabal-install runs.+Tested-With:       GHC==6.10.4+Cabal-Version:     >=1.6+Build-Type:        Simple+Source-Repository head+  type:     darcs+  location: http://code.haskell.org/~thielema/cabal-sort/++Source-Repository this+  type:     darcs+  location: http://code.haskell.org/~thielema/cabal-sort/+  tag:      0.0.1+++Executable cabal-sort+  Build-Depends:+    Cabal >=1.6 && <1.10,+    fgl >=5.4.2 && <5.5,+    directory >=1 && <1.1,+    filepath >=1.1 && <1.2,+    containers >=0.2 && <0.4,+    explicit-exception >=0.1.4 && <0.2,+    transformers >=0.2 && <0.3,+    base >=2 && <5++  GHC-Options:      -Wall+  Hs-source-dirs:   src+  Main-Is:          Main.hs
+ src/Main.hs view
@@ -0,0 +1,169 @@+module Main where++import qualified Distribution.PackageDescription as P+import Distribution.PackageDescription+         (GenericPackageDescription, PackageDescription,+          package, packageDescription, buildDepends, )+import Distribution.PackageDescription.Parse (readPackageDescription, )+import Distribution.Package+         (Dependency(Dependency), PackageName(PackageName), pkgName, )++import qualified Distribution.Verbosity as Verbosity+import qualified Distribution.ReadE as ReadE++import System.Console.GetOpt+          (getOpt, ArgOrder(..), OptDescr(..), ArgDescr(..), usageInfo, )+import System.Exit (exitWith, ExitCode(..), )+import qualified System.Environment as Env+import qualified System.FilePath as FilePath++import Data.Graph.Inductive.Query.DFS (topsort', scc, )+import Data.Graph.Inductive.Tree (Gr, )+import qualified Data.Graph.Inductive.Graph as Graph++import qualified Control.Monad.Exception.Synchronous as Exc+import qualified Control.Monad.Trans.Class as Trans++import qualified Data.Set as Set+import Control.Monad (when, )+import Data.Maybe (mapMaybe, )+++main :: IO ()+main =+   Exc.resolveT (\e -> putStr $ "Aborted: " ++ e ++ "\n") $ do+      argv <- Trans.lift Env.getArgs+      let (opts, cabalPaths, errors) =+             getOpt RequireOrder options argv+      when (not (null errors)) $ Exc.throwT $ concat $ errors+      flags <-+         Exc.ExceptionalT $ return $+            foldr (flip (>>=))+               (return $+                Flags {optHelp = False,+                       optVerbosity = Verbosity.silent,+                       optInfo = location})+               opts+      when (optHelp flags)+         (Trans.lift $+          Env.getProgName >>= \programName ->+          putStrLn+             (usageInfo ("Usage: " ++ programName +++                         " [OPTIONS] CABAL-FILES ...") options) >>+          exitWith ExitSuccess)++      Trans.lift $ sortCabalFiles flags cabalPaths+++data Flags =+   Flags {+      optHelp :: Bool,+      optVerbosity :: Verbosity.Verbosity,+      optInfo :: SourcePackage -> String+   }++options :: [OptDescr (Flags -> Exc.Exceptional String Flags)]+options =+   Option ['h'] ["help"]+      (NoArg (\flags -> return $ flags{optHelp = True}))+      "show options" :+   Option ['v'] ["verbose"]+      (ReqArg+         (\str flags ->+            fmap (\n -> flags{optVerbosity = n}) $+            Exc.fromEither $+            ReadE.runReadE Verbosity.flagToVerbosity str)+         "N")+      "verbosity level: 0..3" :+   Option [] ["info"]+      (ReqArg+         (\str flags ->+            fmap (\select -> flags{optInfo = select}) $+            case str of+               "name" -> Exc.Success+                            (getPkgName . pkgName . package .+                             packageDescription . description)+               "path" -> Exc.Success location+               "dir"  -> Exc.Success (FilePath.takeDirectory . location)+               _ ->+                  Exc.Exception $+                  "unknown info type " ++ str)+         "KIND")+      "kind of output: name, path, dir" :+   []++++data SourcePackage =+   SourcePackage {+      location :: FilePath,+      description :: GenericPackageDescription+   }++sortCabalFiles :: Flags -> [FilePath] -> IO ()+sortCabalFiles flags cabalPaths =+   do pkgDescs <-+         mapM (readPackageDescription (optVerbosity flags)) cabalPaths+      when (optVerbosity flags >= Verbosity.verbose) $+         flip mapM_ pkgDescs $ \pkgDesc -> do+            putStrLn+               ((getPkgName . pkgName . package . packageDescription $ pkgDesc) ++ ":")+            let deps =+                   Set.toAscList $ Set.fromList $+                   map (getPkgName . depName) $+                   allDependencies pkgDesc+            flip mapM_ deps $ \dep ->+               putStrLn $ "  " ++ dep+      mapM_ (putStrLn . optInfo flags) $+         getBuildOrder $+         zipWith SourcePackage cabalPaths pkgDescs+++getBuildOrder ::+   [SourcePackage] ->+   [SourcePackage]+getBuildOrder srcPkgs =+   let nodes = zip [0..] srcPkgs+       nodeDict =+          zip+             (map (pkgName . package . packageDescription . description)+                  srcPkgs)+             [0..]+       edges = do+          (srcNode,desc) <- nodes+          dstNode <-+             mapMaybe+                (flip lookup nodeDict . depName)+                (allDependencies $ description desc)+          return (dstNode, srcNode, ())+       graph :: Gr SourcePackage ()+       graph = Graph.mkGraph nodes edges++   in  if hasCycle graph+         then error "cycle in dependencies"+         else topsort' graph++allDependencies :: GenericPackageDescription -> [Dependency]+allDependencies pkg =+   P.buildDepends (packageDescription pkg) +++   maybe [] (concatMap snd . flattenCondTree) (P.condLibrary pkg) +++   concatMap (concatMap snd . flattenCondTree . snd) (P.condExecutables pkg)++flattenCondTree :: P.CondTree v c a -> [(a,c)]+flattenCondTree tree =+   (P.condTreeData tree, P.condTreeConstraints tree) :+   concatMap+      (\(_, thenBranch, elseBranch) ->+         flattenCondTree thenBranch +++         maybe [] flattenCondTree elseBranch)+      (P.condTreeComponents tree)++depName :: Dependency -> PackageName+depName (Dependency name _) = name++getPkgName :: PackageName -> String+getPkgName (PackageName name) = name++hasCycle :: Gr a b -> Bool+hasCycle graph =+   length (scc graph) < length (Graph.nodes graph)