packages feed

diffcabal (empty) → 0.1

raw patch · 4 files changed

+298/−0 lines, 4 filesdep +Cabaldep +Diffdep +basesetup-changed

Dependencies added: Cabal, Diff, base, bytestring, containers, directory, filepath, pretty, process

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2008 Don Stewart++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.++2. 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.++3. Neither the name of the author nor the names of his contributors+   may be used to endorse or promote products derived from this software+   without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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.
+ Main.hs view
@@ -0,0 +1,226 @@+-- |+-- Module    : diffcabal: diff two cabal files+-- Copyright : (c) Don Stewart, 2010+-- License   : BSD3+--+-- Maintainer: Don Stewart <dons@galois.com>+-- Stability : provisional+-- Portability:+--++import Distribution.PackageDescription+import Distribution.PackageDescription.Parse+import Distribution.Simple.Utils hiding (die, intercalate)+import Distribution.Verbosity+import Distribution.Package+import Distribution.ModuleName hiding (main)+import Distribution.PackageDescription.Configuration+import Distribution.Text+import Distribution.Version++import Data.Algorithm.Diff+import Data.Function++import Control.Monad+import Control.Concurrent+import Control.Exception+import qualified Control.OldException as C++import System.Directory+import System.Environment+import System.Exit+import System.FilePath+import System.IO+import System.Process hiding (cwd)++import Data.List+import Data.Maybe+import Data.Char++import Text.PrettyPrint++main :: IO ()+main =+ bracket+   -- We do all our work in a temp directory+  (do cwd  <- getCurrentDirectory+      etmp <- makeTempDir+      case etmp of+        Left _  -> die "Unable to create temp directory"+        Right d -> do+            let dir = makeValid (init d) -- drop newline+            setCurrentDirectory dir+            return (dir, cwd))++   -- Always remember to clean up+  (\(d,cwd) -> do+            setCurrentDirectory cwd+            removeDirectoryRecursive d)++   -- Now, get to work:+  $ \(tmp,cwd) -> do++   res <- do x <- getArgs+             case x of+               ["--help"] -> help+               ["-h"]     -> help+               (f1:f2:[]) -> return [f1,f2]+               _          -> help++   modules' <- forM res $ \f -> do++       cabalfile <- findCabalFile f cwd tmp+++       cabalsrc  <- readPackageDescription normal cabalfile+       let final =  flattenPackageDescription cabalsrc+           dependencies  = buildDepends final +++                                concatMap buildTools+                                (allBuildInfo final)++       return (final, dependencies)+++------------------------------------------------------------------------++   -- diff the dependencies.++   let diff =+        groupBy ((==) `on` (name . snd)) $+        sortBy (comparing (name . snd))+            [ (t, d)+            | (t, d) <-+              getDiff (sortBy (comparing name) . snd $ modules' !! 0)+                      (sortBy (comparing name) . snd $ modules' !! 1)++            , t /= B -- strip stuff that is equal++            ]++   mapM_ (putStrLn . render . pprDiff) diff++------------------------------------------------------------------------++name (Dependency n _) = n+vers (Dependency _ v) = v++precise (ThisVersion v) = v+++pprDiff :: [(DI, Dependency)] -> Doc+pprDiff [(S, b), (F, a)] =+    hang+        (disp (name a))+        4 $+        disp (precise $ vers a) <+> text "->" <+> disp (precise $ vers b)++------------------------------------------------------------------------++makeTempDir :: IO (Either (ExitCode, String, String) String)+makeTempDir = myReadProcess "mktemp" ["-d", "-t", "fooXXXX"] []++------------------------------------------------------------------------++-- Return the path to a .cabal file.+-- If not arguments are specified, use ".",+-- if the argument looks like a url, download that+-- otherwise, assume its a directory+--+findCabalFile :: FilePath -> FilePath -> FilePath -> IO FilePath+findCabalFile file cwd tmp = do+   let epath | null file+                = Right cwd+             | "http://" `isPrefixOf` file+                = Left file+             | ".cabal"  `isSuffixOf` file+                = Right (makeValid (joinPath [cwd,file]))+             | otherwise  -- a relative directory path+                = Right (cwd </> file)++   -- download url to .cabal+   case epath of+       Left url -> do+        eres <- myReadProcess "wget" [url] []+        case eres of+           Left (_,s,_) -> do+                hPutStrLn stderr s+                die $ "Couldn't download .cabal file: " ++ show url+           Right _ ->+                findPackageDesc tmp -- tmp dir -- error: only allows one url on the command line++   -- it might be a .cabal file+       Right f | ".cabal" `isSuffixOf` f -> do+         b <- doesFileExist f+         if not b+            then die $ ".cabal file doesn't exist: " ++ show f+            else return f++   -- or assume it is a dir to a file:+       Right dir -> do+         b <- doesDirectoryExist dir+         if not b+            then die $ "directory doesn't exist: " ++ show dir+            else findPackageDesc dir++die :: String -> IO a+die s = do+    hPutStrLn stderr $ "cabalgraph:\n" ++ s+    exitWith (ExitFailure 1)++help :: IO a+help = do+ hPutStrLn stderr $ unlines+    [ "diffcabal [-h|--help] [file|directory|url] [file|directory|url]"+    , ""+    , "  Diff two .cabal files syntactically"+    , ""+    , "Usage:"+    , "   -h    Display help message"+    , ""+    , "Arguments: <directory>"+    , "              Look for .cabal file in <directory>"+    , "              If directory is empty, use pwd"+    , "           <file.cabal>"+    , "              Use .cabal file as source"+    , "           <url>"+    , "              Download .cabal file from <url>"+    ]+ exitWith ExitSuccess++------------------------------------------------------------------------++--+-- Strict process reading +--+myReadProcess :: FilePath                              -- ^ command to run+            -> [String]                              -- ^ any arguments+            -> String                                -- ^ standard input+            -> IO (Either (ExitCode,String,String) String)  -- ^ either the stdout, or an exitcode and any output++myReadProcess cmd args input = C.handle (return . handler) $ do+    (inh,outh,errh,pid) <- runInteractiveProcess cmd args Nothing Nothing++    output  <- hGetContents outh+    outMVar <- newEmptyMVar+    forkIO $ (C.evaluate (length output) >> putMVar outMVar ())++    errput  <- hGetContents errh+    errMVar <- newEmptyMVar+    forkIO $ (C.evaluate (length errput) >> putMVar errMVar ())++    when (not (null input)) $ hPutStr inh input+    takeMVar outMVar+    takeMVar errMVar+    ex     <- C.catch (waitForProcess pid) (\_e -> return ExitSuccess)+    hClose outh+    hClose inh          -- done with stdin+    hClose errh         -- ignore stderr++    return $ case ex of+        ExitSuccess   -> Right output+        ExitFailure _ -> Left (ex, errput, output)++  where+    handler (C.ExitException e) = Left (e,"","")+    handler e                   = Left (ExitFailure 1, show e, "")+
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ diffcabal.cabal view
@@ -0,0 +1,39 @@+name:               diffcabal+version:            0.1+license:            BSD3+license-file:       LICENSE+author:             Don Stewart+maintainer:         dons@galois.com+homepage:           http://code.haskell.org/~dons/code/diffcabal+category:           Distribution+synopsis:           Diff two .cabal files syntactically+description:        Diff two .cabal files syntactically+                    The cabal files may be in the current directly, specified directly, or+                    live on a url far away.+                    .+                    Example:+                    .+                    > $ diffcabal haskell-platform.cabal http://hackage.haskell.org/platform/2010.1.0.0/haskell-platform.cabal         +                    > QuickCheck 2.1.1.1 -> 2.1.0.3+                    > alex 2.3.3 -> 2.3.2+                    > cabal-install 0.8.2 -> 0.8.0+                    > cgi 3001.1.7.3 -> 3001.1.7.2+                    > fgl 5.4.2.3 -> 5.4.2.2+                    > happy 1.18.5 -> 1.18.4+                    .+cabal-version:      >= 1.2+build-type:         Simple++executable diffcabal+    main-is:            Main.hs++    build-depends:+            base >= 4 && < 5,+            Cabal   > 1.6,+            pretty,+            process,+            directory,+            containers,+            bytestring,+            filepath,+            Diff