3-- Copyright (c) 20011 Peter Simons <simons@cryp.to>
4-- See LICENSE file for licensing details.
6module Main ( main ) where
9import System.Environment
10import Control.Exception
12import Distribution.PackageDescription.Parse
13import Distribution.PackageDescription
14import Distribution.Package
15import Distribution.License
24type PkgVersion = [Int]
25type PkgSHA256 = String
27type PkgDescription = String
28type PkgLicense = License
29type PkgDependencies = [CondTree ConfVar [Dependency] ()]
30type PkgExtraLibs = [String]
32data Pkg = Pkg PkgName PkgVersion PkgSHA256 PkgURL PkgDescription PkgLicense PkgDependencies PkgExtraLibs
35toNixName :: String -> String
36toNixName [] = error "toNixName: empty string is not a valid argument"
37toNixName "Cabal" = "cabal"
38toNixName name = f name
41 f ('-':c:cs) | c `notElem` "-" = toUpper c : f cs
42 f ('-':_) = error ("unexpected package name " ++ show name)
46toNix (Pkg name ver sha256 url desc lic deps libs) =
47 "{" ++ exprArgs ++"}:\n\n"
48 ++ "cabal.mkDerivation (self : {\n"
49 ++ " pname = " ++ show name ++ ";\n"
50 ++ " version = \"" ++ showVer ++ "\";\n"
51 ++ " sha256 = " ++ show sha256 ++ ";\n"
52 ++ " propagatedBuildInputs = [" ++ depList ++ "];\n"
54 ++ " homepage = \"" ++ url ++ "\";\n"
55 ++ " description = " ++ show desc ++ ";\n"
56 ++ " license = " ++ showLic lic ++ ";\n"
60 exprArgs = concat (intersperse "," ("cabal":pkgDeps))
61 showVer = concat (intersperse "." (map show ver))
62 depList = concat (intersperse " " pkgDeps)
64 pkgDeps = filter (/="cabal") $ nub $ sort $ map toNixName $
65 libs ++ [ n | dep <- deps, Dependency (PackageName n) _ <- condTreeConstraints dep
66 , n `notElem` ["base","containers"]
68 showLic (GPL Nothing) = show "GPL"
69 showLic (GPL (Just (Version [2] []))) = "self.stdenv.lib.licenses.gpl2"
70 showLic (GPL (Just (Version [3] []))) = "self.stdenv.lib.licenses.gpl3"
71 showLic (LGPL Nothing) = show "LGPL"
72 showLic (LGPL (Just (Version [2,1] []))) = "self.stdenv.lib.licenses.lgpl21"
73 showLic (LGPL (Just (Version [3] []))) = "self.stdenv.lib.licenses.lgpl3"
74 showLic BSD3 = "self.stdenv.lib.licenses.bsd3"
75 showLic BSD4 = "self.stdenv.lib.licenses.bsd4"
76 showLic MIT = "self.stdenv.lib.licenses.mit"
77 showLic PublicDomain = "self.stdenv.lib.licenses.publicDomain"
78 showLic AllRightsReserved = "unknown"
79 showLic OtherLicense = "unknown"
80 showLic l = error $ "unknown license: " ++ show l
82cabal2nix :: GenericPackageDescription -> PkgSHA256 -> Pkg
83cabal2nix cabal sha256 = Pkg pkgname pkgver sha256 url desc lic (map simplify libDeps ++ map simplify exeDeps) (libs++libs')
85 pkg = packageDescription cabal
86 PackageName pkgname = pkgName (package pkg)
87 pkgver = versionBranch (pkgVersion (package pkg))
91 -- globalDeps = buildDepends pkg
92 libDeps = maybe [] (\x -> [x]) (condLibrary cabal)
93 exeDeps = [ tree | (_,tree) <- condExecutables cabal ]
94 libs = concat [ extraLibs (libBuildInfo (condTreeData x)) | x <- libDeps ]
95 libs' = concat [ extraLibs (buildInfo (condTreeData x)) | x <- exeDeps ]
97simplify :: CondTree ConfVar [Dependency] a -> CondTree ConfVar [Dependency] ()
98simplify (CondNode _ deps nodes) = CondNode () deps (map simp nodes)
100 simp (cond,tree,mtree) = (cond, simplify tree, maybe Nothing (Just . simplify) mtree)
102readCabalFile :: FilePath -> IO String
104 | "http://" `isPrefixOf` path = Network.HTTP.simpleHTTP (getRequest path) >>= getResponseBody
105 | "file://" `isPrefixOf` path = readCabalFile (drop 7 path)
106 | otherwise = readFile path
108hashPackage :: GenericPackageDescription -> IO String
109hashPackage pkg = readProcess "bash" ["-c", "exec nix-prefetch-url 2>/dev/tty " ++ url] ""
111 url = "http://hackage.haskell.org/packages/archive/" ++ name ++ "/" ++ version ++ "/" ++ name ++ "-" ++ version ++ ".tar.gz"
112 PackageIdentifier (PackageName name) version' = package (packageDescription pkg)
113 version = showVersion version'
116main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
119 let usage = "Usage: cabal2nix url-to-cabal-file [sha256-hash]"
121 when (length args < 1 || length args > 2) $ do
122 mapM_ (hPutStrLn stderr) [ "*** invalid command line syntax"
127 when ("--help" `elem` args || "-h" `elem` args) $ do
131 cabal' <- fmap parsePackageDescription (readCabalFile (head args))
132 cabal <- case cabal' of
133 ParseOk _ a -> return a
134 ParseFailed err -> do
135 hPutStrLn stderr ("*** cannot parse cabal file: " ++ show err)
138 sha256 <- case args of
139 _:hash:[] -> return hash
140 _ -> hashPackage cabal
142 let pkg = cabal2nix cabal sha256
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list