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 +30/−0
- Main.hs +226/−0
- Setup.lhs +3/−0
- diffcabal.cabal +39/−0
+ 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