diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -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, "")
+
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/diffcabal.cabal b/diffcabal.cabal
new file mode 100644
--- /dev/null
+++ b/diffcabal.cabal
@@ -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
