diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Benjamen Armston
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cabal-constraints.cabal b/cabal-constraints.cabal
new file mode 100644
--- /dev/null
+++ b/cabal-constraints.cabal
@@ -0,0 +1,107 @@
+name:                cabal-constraints
+-- The package version.  See the Haskell package versioning policy (PVP) 
+-- for standards guiding when and how versions should be incremented.
+-- http://www.haskell.org/haskellwiki/Package_versioning_policy
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.0.0.1
+synopsis:            Repeatable builds for cabalized Haskell projects.
+description:
+    /Repeatable builds for cabalized Haskell projects/
+    .
+    \'cabal-constraints\' provides repeatable builds for cabalized Haskell
+    projects by \"freezing\" the exact versions of the dependencies selected by
+    \'cabal-install\'. All build environments for the project, such as the test
+    or staging build environments, or other developers collaborating on the
+    project, will then use the same dependency versions.
+    .
+    It is designed to be used alongside \'cabal-install\' sandboxes, in which
+    case isolated, repeatable builds can be achieved.
+    .
+    /Using cabal-constraints/
+    .
+    \'cabal-constraints\' should be run from the root directory of a cabalized
+    Haskell project and given the path to the `setup-config` file to use. It will
+    print out all dependencies of the project in a format suitable for use in a
+    `cabal-install` config file. For example, running \'cabal-constraints\'
+    against itself produces the following:
+    .
+    @
+    $ cabal-constraints dist\/dist-sandbox-500003c6\/setup-config
+    constraints: Cabal == 1.19.0
+               , array == 0.4.0.1
+               , base == 4.6.0.1
+               , bytestring == 0.10.0.2
+               , containers == 0.5.0.0
+               , deepseq == 1.3.0.1
+               , directory == 1.2.0.1
+               , filepath == 1.3.0.1
+               , ghc-prim == 0.3.0.0
+               , integer-gmp == 0.5.0.0
+               , old-locale == 1.0.0.5
+               , pretty == 1.1.1.0
+               , process == 1.1.0.2
+               , rts == 1.0
+               , time == 1.4.0.1
+               , unix == 2.6.0.1
+    @
+    .
+    A single mandatory argument must be provided which is the path to the
+    @setup-config@ file to use. The file will be located under the @dist@
+    directory. Usually there will be a single @setup-config@ file which can be
+    found by running @find dist -name setup-config@ from the root directory of the
+    project.  If your project has more than one such file, it is likely because
+    you have built it either with and without sandboxes or with multiple
+    sandboxes.  You probably want the most recently modified file which can be
+    found with @ls -tr $( find dist -name setup-config ) | tail -n1@.
+    .
+    To use these constraints for reproducible builds, one should make use of the
+    new sandbox feature of @cabal-install@ 1.18. The constraints can be redirected
+    to @cabal.config@ and committed to your code repository.  When the project is
+    built, the same set of dependency versions will be resolved by @cabal-install@
+    ensuring repeatable builds.
+    .
+    If @cabal.config@ contains no other information the simplest solution is to
+    overwrite it:
+    .
+    @
+    $ cabal-constraints > cabal.config
+    @
+    .
+    If @cabal.config@ contains information that needs to be preserved, the
+    following will replace the @constraints@ section and everything following it
+    with the new constraints. If you ensure that the @constraints@ section is the
+    last section of the file, all other information in it will be kept.
+    .
+    @
+    $ sed -i \/^constraints:\/,$d cabal.config && cabal-constraints >> cabal.config
+    @
+
+
+homepage:            https://github.com/benarmston/cabal-constraints
+license:             MIT
+license-file:        LICENSE
+author:              Ben Armston
+maintainer:          ben.armston@googlemail.com
+-- A copyright notice.
+-- copyright:           
+category:            Development, Distribution
+build-type:          Simple
+cabal-version:       >=1.8
+
+source-repository head
+  type: git
+  location: https://github.com/benarmston/cabal-constraints.git
+
+executable cabal-constraints
+  -- .hs or .lhs file containing the Main module.
+  main-is:             src/CabalConstraints.hs
+  
+  -- Modules included in this executable, other than Main.
+  -- other-modules:       
+  
+  -- Other library packages from which modules are imported.
+  build-depends:       base ==4.6.*
+                     , Cabal >= 1.18
+                     , optparse-applicative >= 0.5.2.1
diff --git a/src/CabalConstraints.hs b/src/CabalConstraints.hs
new file mode 100644
--- /dev/null
+++ b/src/CabalConstraints.hs
@@ -0,0 +1,93 @@
+import Data.Maybe (fromMaybe)
+import Data.Function (on)
+import Data.List (intercalate, sortBy)
+import Data.Version (showVersion)
+
+import Distribution.Package (PackageName(PackageName), Dependency(Dependency), pkgVersion)
+import Distribution.Simple.Configure (tryGetConfigStateFile)
+import Distribution.Simple.PackageIndex (allPackagesByName)
+import Distribution.InstalledPackageInfo (sourcePackageId)
+import Distribution.Simple.LocalBuildInfo (LocalBuildInfo, configFlags, installedPkgs)
+import Distribution.Simple.Setup (configConstraints)
+import Distribution.Version (Version, isSpecificVersion)
+
+import Options.Applicative
+
+data Args = Args { depth           :: Depth
+                 , setupConfigPath :: String
+                 }
+
+data Depth = Deep | Shallow
+
+
+options :: Parser Args
+options =  Args
+    <$> flag Deep Shallow
+        (  long "shallow"
+        <> help "Only show the dependencies specified in the .cabal file"
+        )
+    <*> argument Just
+        (  metavar "<PATH TO setup-config>"
+        <> action "file"
+        )
+
+
+main :: IO ()
+main = execParser opts >>= printConstraints
+  where
+    opts = info (helper <*> options)
+        ( fullDesc
+        <> progDesc (unlines [ "Show exact dependency constraints for a cabal project, by reading"
+                             , "  the setup-config file located at PATH, defaulting to \"dist/setup-config\"."
+                             ])
+        )
+
+
+printConstraints :: Args -> IO ()
+printConstraints args = do
+    let deps = case depth args of
+                   Deep    -> deepDeps
+                   Shallow -> shallowDeps
+    lbi' <- tryGetConfigStateFile (setupConfigPath args)
+    either printError (putStrLn . formattedConstraints . deps) lbi'
+  where
+    printError = putStrLn . fst
+
+
+shallowDeps :: LocalBuildInfo -> [(PackageName, [Version])]
+shallowDeps = sortBy (compare `on` fst)
+            . map format . configConstraints . configFlags
+  where
+    format dependency@(Dependency name versionRange) =
+        let version = fromMaybe (error $ errorMsg dependency)
+                                (isSpecificVersion versionRange)
+        in (name, [version])
+    errorMsg dependency =
+        "malformed setup-config: " ++
+        "dependency is not constrained to a specific version: "
+        ++ show dependency
+
+
+deepDeps :: LocalBuildInfo -> [(PackageName, [Version])]
+deepDeps = map format
+         . allPackagesByName
+         . installedPkgs
+  where
+    format (name, pkgInfos) = (name, map (pkgVersion. sourcePackageId) pkgInfos)
+
+
+formattedConstraints :: [(PackageName, [Version])] -> String
+formattedConstraints = (prefix ++)
+                     . intercalate separator
+                     . map formatConstraint
+  where
+    prefix = "constraints: "
+    separator = "\n" ++ replicate (length prefix - 2) ' ' ++ ", " 
+
+
+formatConstraint :: (PackageName, [Version]) -> String
+formatConstraint (PackageName name, versions) =
+    name ++ " == " ++ allVersionConstraints versions
+  where
+    allVersionConstraints = intercalate " || "
+                          . map showVersion
