git.iko.soy/typeable/cabal2nix
on master help sign in
Merge pull request #1 from kosmikus/master

Refactoring and cabal://pkg-version URIs.

commit16ef3cb8249996b18617710b6f8d7eea6ed231ef authorPeter Simons <simons@cryp.to> dateSat 6 Aug 2011, 04:33 (15 years ago) parent208d4c3cf7f665
6 files changed+196−149
cabal2nix.cabal+2−1 cabal2nix.hs−148 src/Cabal2Nix.hs+86 src/Cabal2Nix/License.hs+21 src/Cabal2Nix/Name.hs+13 src/Cabal2Nix/Package.hs+74
cabal2nix.cabal+2−1
@@ -35,6 +35,7 @@ Source-Repository head
3535 Location: git://github.com/peti/cabal2nix.git
3636
3737Executable cabal2nix
38− main-is: cabal2nix.hs
38+ main-is: Cabal2Nix.hs
39+ hs-source-dirs: src
3940 Build-Depends: base >= 3 && < 5, Cabal, process, HTTP
4041 Ghc-Options: -Wall
cabal2nix.hsdeleted−148
@@ -1,148 +0,0 @@
1−-- cabal2nix.hs
2−--
3−-- Copyright (c) 20011 Peter Simons <simons@cryp.to>
4−-- See LICENSE file for licensing details.
5−
6−module Main ( main ) where
7−
8−import System.IO
9−import System.Environment
10−import Control.Exception
11−import System.Exit
12−import Distribution.PackageDescription.Parse
13−import Distribution.PackageDescription
14−import Distribution.Package
15−import Distribution.License
16−import Data.Version
17−import Data.List
18−import Control.Monad
19−import Data.Char
20−import Network.HTTP
21−import System.Process
22−
23−type PkgName = String
24−type PkgVersion = [Int]
25−type PkgSHA256 = String
26−type PkgURL = String
27−type PkgDescription = String
28−type PkgLicense = License
29−type PkgDependencies = [CondTree ConfVar [Dependency] ()]
30−type PkgExtraLibs = [String]
31−
32−data Pkg = Pkg PkgName PkgVersion PkgSHA256 PkgURL PkgDescription PkgLicense PkgDependencies PkgExtraLibs
33− deriving (Show)
34−
35−toNixName :: String -> String
36−toNixName [] = error "toNixName: empty string is not a valid argument"
37−toNixName "Cabal" = "cabal"
38−toNixName name = f name
39− where
40− f [] = []
41− f ('-':c:cs) | c `notElem` "-" = toUpper c : f cs
42− f ('-':_) = error ("unexpected package name " ++ show name)
43− f (c:cs) = c : f cs
44−
45−toNix :: Pkg -> String
46−toNix (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"
53− ++ " meta = {\n"
54− ++ " homepage = \"" ++ url ++ "\";\n"
55− ++ " description = " ++ show desc ++ ";\n"
56− ++ " license = " ++ showLic lic ++ ";\n"
57− ++ " };\n"
58− ++ "})\n"
59− where
60− exprArgs = concat (intersperse "," ("cabal":pkgDeps))
61− showVer = concat (intersperse "." (map show ver))
62− depList = concat (intersperse " " pkgDeps)
63− pkgDeps :: [String]
64− pkgDeps = filter (/="cabal") $ nub $ sort $ map toNixName $
65− libs ++ [ n | dep <- deps, Dependency (PackageName n) _ <- condTreeConstraints dep
66− , n `notElem` ["base","containers"]
67− ]
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
81−
82−cabal2nix :: GenericPackageDescription -> PkgSHA256 -> Pkg
83−cabal2nix cabal sha256 = Pkg pkgname pkgver sha256 url desc lic (map simplify libDeps ++ map simplify exeDeps) (libs++libs')
84− where
85− pkg = packageDescription cabal
86− PackageName pkgname = pkgName (package pkg)
87− pkgver = versionBranch (pkgVersion (package pkg))
88− lic = license pkg
89− url = homepage pkg
90− desc = synopsis 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 ]
96−
97−simplify :: CondTree ConfVar [Dependency] a -> CondTree ConfVar [Dependency] ()
98−simplify (CondNode _ deps nodes) = CondNode () deps (map simp nodes)
99− where
100− simp (cond,tree,mtree) = (cond, simplify tree, maybe Nothing (Just . simplify) mtree)
101−
102−readCabalFile :: FilePath -> IO String
103−readCabalFile path
104− | "http://" `isPrefixOf` path = Network.HTTP.simpleHTTP (getRequest path) >>= getResponseBody
105− | "file://" `isPrefixOf` path = readCabalFile (drop 7 path)
106− | otherwise = readFile path
107−
108−hashPackage :: GenericPackageDescription -> IO String
109−hashPackage pkg = do
110− hash <- readProcess "bash" ["-c", "exec nix-prefetch-url 2>/dev/tty " ++ url] ""
111− return (reverse (dropWhile (=='\n') (reverse hash)))
112−
113− where
114− url = "http://hackage.haskell.org/packages/archive/" ++ name ++ "/" ++ version ++ "/" ++ name ++ "-" ++ version ++ ".tar.gz"
115− PackageIdentifier (PackageName name) version' = package (packageDescription pkg)
116− version = showVersion version'
117−
118−main :: IO ()
119−main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
120− args <- getArgs
121−
122− let usage = "Usage: cabal2nix url-to-cabal-file [sha256-hash]"
123−
124− when (length args < 1 || length args > 2) $ do
125− mapM_ (hPutStrLn stderr) [ "*** invalid command line syntax"
126− , usage
127− ]
128− exitFailure
129−
130− when ("--help" `elem` args || "-h" `elem` args) $ do
131− putStrLn usage
132− exitFailure
133−
134− cabal' <- fmap parsePackageDescription (readCabalFile (head args))
135− cabal <- case cabal' of
136− ParseOk _ a -> return a
137− ParseFailed err -> do
138− hPutStrLn stderr ("*** cannot parse cabal file: " ++ show err)
139− exitFailure
140−
141− sha256 <- case args of
142− _:hash:[] -> return hash
143− _ -> hashPackage cabal
144−
145− let pkg = cabal2nix cabal sha256
146− putStr (toNix pkg)
147−
148−
src/Cabal2Nix.hsnew file+86
@@ -0,0 +1,86 @@
1+-- cabal2nix.hs
2+--
3+-- Copyright (c) 20011 Peter Simons <simons@cryp.to>
4+-- See LICENSE file for licensing details.
5+
6+module Main ( main ) where
7+
8+import System.IO
9+import System.Environment
10+import Control.Exception
11+import System.Exit
12+import Distribution.PackageDescription.Parse
13+import Distribution.PackageDescription
14+import Distribution.Package
15+import Distribution.Text
16+import Data.Version
17+import Data.List
18+import Control.Monad
19+import Network.HTTP
20+import System.Process
21+
22+import Cabal2Nix.Package
23+
24+
25+data Ext = TarGz | Cabal deriving Eq
26+
27+showExt :: Ext -> String
28+showExt TarGz = ".tar.gz"
29+showExt Cabal = ".cabal"
30+
31+hackagePath :: PackageIdentifier -> Ext -> String
32+hackagePath (PackageIdentifier (PackageName name) version') ext =
33+ "http://hackage.haskell.org/packages/archive/" ++
34+ name ++ "/" ++ version ++ "/" ++ name ++
35+ (if ext == TarGz then "-" ++ version else "") ++
36+ showExt ext
37+ where
38+ version = showVersion version'
39+
40+readCabalFile :: FilePath -> IO String
41+readCabalFile path
42+ | "cabal://" `isPrefixOf` path = let Just pid = simpleParse (drop 8 path) in readCabalFile (hackagePath pid Cabal)
43+ | "http://" `isPrefixOf` path = Network.HTTP.simpleHTTP (getRequest path) >>= getResponseBody
44+ | "file://" `isPrefixOf` path = readCabalFile (drop 7 path)
45+ | otherwise = readFile path
46+
47+hashPackage :: GenericPackageDescription -> IO String
48+hashPackage pkg = do
49+ hash <- readProcess "bash" ["-c", "exec nix-prefetch-url 2>/dev/tty " ++ url] ""
50+ return (reverse (dropWhile (=='\n') (reverse hash)))
51+
52+ where
53+ url = hackagePath pid TarGz
54+ pid = package (packageDescription pkg)
55+
56+main :: IO ()
57+main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
58+ args <- getArgs
59+
60+ let usage = "Usage: cabal2nix url-to-cabal-file [sha256-hash]"
61+
62+ when (length args < 1 || length args > 2) $ do
63+ mapM_ (hPutStrLn stderr) [ "*** invalid command line syntax"
64+ , usage
65+ ]
66+ exitFailure
67+
68+ when ("--help" `elem` args || "-h" `elem` args) $ do
69+ putStrLn usage
70+ exitFailure
71+
72+ cabal' <- fmap parsePackageDescription (readCabalFile (head args))
73+ cabal <- case cabal' of
74+ ParseOk _ a -> return a
75+ ParseFailed err -> do
76+ hPutStrLn stderr ("*** cannot parse cabal file: " ++ show err)
77+ exitFailure
78+
79+ sha256 <- case args of
80+ _:hash:[] -> return hash
81+ _ -> hashPackage cabal
82+
83+ let pkg = cabal2nix cabal sha256
84+ putStr (toNix pkg)
85+
86+
src/Cabal2Nix/License.hsnew file+21
@@ -0,0 +1,21 @@
1+module Cabal2Nix.License
2+ (module Cabal2Nix.License, module Distribution.License)
3+ where
4+
5+import Distribution.License
6+import Distribution.Version
7+
8+showLic :: License -> String
9+showLic (GPL Nothing) = show "GPL"
10+showLic (GPL (Just (Version [2] []))) = "self.stdenv.lib.licenses.gpl2"
11+showLic (GPL (Just (Version [3] []))) = "self.stdenv.lib.licenses.gpl3"
12+showLic (LGPL Nothing) = show "LGPL"
13+showLic (LGPL (Just (Version [2,1] []))) = "self.stdenv.lib.licenses.lgpl21"
14+showLic (LGPL (Just (Version [3] []))) = "self.stdenv.lib.licenses.lgpl3"
15+showLic BSD3 = "self.stdenv.lib.licenses.bsd3"
16+showLic BSD4 = "self.stdenv.lib.licenses.bsd4"
17+showLic MIT = "self.stdenv.lib.licenses.mit"
18+showLic PublicDomain = "self.stdenv.lib.licenses.publicDomain"
19+showLic AllRightsReserved = "unknown"
20+showLic OtherLicense = "unknown"
21+showLic l = error $ "unknown license: " ++ show l
src/Cabal2Nix/Name.hsnew file+13
@@ -0,0 +1,13 @@
1+module Cabal2Nix.Name where
2+
3+import Data.Char
4+
5+toNixName :: String -> String
6+toNixName [] = error "toNixName: empty string is not a valid argument"
7+toNixName "Cabal" = "cabal"
8+toNixName name = f name
9+ where
10+ f [] = []
11+ f ('-':c:cs) | c `notElem` "-" = toUpper c : f cs
12+ f ('-':_) = error ("unexpected package name " ++ show name)
13+ f (c:cs) = c : f cs
src/Cabal2Nix/Package.hsnew file+74
@@ -0,0 +1,74 @@
1+module Cabal2Nix.Package where
2+
3+import Data.List
4+import Data.Maybe
5+
6+import Distribution.Package
7+import Distribution.PackageDescription
8+import Distribution.Version
9+
10+import Cabal2Nix.License
11+import Cabal2Nix.Name
12+
13+type PkgName = String
14+type PkgVersion = [Int]
15+type PkgSHA256 = String
16+type PkgURL = String
17+type PkgDescription = String
18+type PkgLicense = License
19+type PkgDependencies = [CondTree ConfVar [Dependency] ()]
20+type PkgExtraLibs = [String]
21+
22+data Pkg = Pkg PkgName
23+ PkgVersion
24+ PkgSHA256
25+ PkgURL
26+ PkgDescription
27+ PkgLicense
28+ PkgDependencies
29+ PkgExtraLibs
30+ deriving (Show)
31+
32+toNix :: Pkg -> String
33+toNix (Pkg name ver sha256 url desc lic deps libs) =
34+ "{" ++ exprArgs ++"}:\n\n"
35+ ++ "cabal.mkDerivation (self : {\n"
36+ ++ " pname = " ++ show name ++ ";\n"
37+ ++ " version = \"" ++ showVer ++ "\";\n"
38+ ++ " sha256 = " ++ show sha256 ++ ";\n"
39+ ++ " propagatedBuildInputs = [" ++ depList ++ "];\n"
40+ ++ " meta = {\n"
41+ ++ " homepage = \"" ++ url ++ "\";\n"
42+ ++ " description = " ++ show desc ++ ";\n"
43+ ++ " license = " ++ showLic lic ++ ";\n"
44+ ++ " };\n"
45+ ++ "})\n"
46+ where
47+ exprArgs = concat (intersperse "," ("cabal":pkgDeps))
48+ showVer = concat (intersperse "." (map show ver))
49+ depList = concat (intersperse " " pkgDeps)
50+ pkgDeps :: [String]
51+ pkgDeps = filter (/="cabal") $ nub $ sort $ map toNixName $
52+ libs ++ [ n | dep <- deps, Dependency (PackageName n) _ <- condTreeConstraints dep
53+ , n `notElem` ["base","containers"]
54+ ]
55+
56+cabal2nix :: GenericPackageDescription -> PkgSHA256 -> Pkg
57+cabal2nix cabal sha256 = Pkg pkgname pkgver sha256 url desc lic (map simplify libDeps ++ map simplify exeDeps) (libs++libs')
58+ where
59+ pkg = packageDescription cabal
60+ PackageName pkgname = pkgName (package pkg)
61+ pkgver = versionBranch (pkgVersion (package pkg))
62+ lic = license pkg
63+ url = homepage pkg
64+ desc = synopsis pkg
65+ -- globalDeps = buildDepends pkg
66+ libDeps = maybeToList (condLibrary cabal)
67+ exeDeps = [ tree | (_,tree) <- condExecutables cabal ]
68+ libs = concat [ extraLibs (libBuildInfo (condTreeData x)) | x <- libDeps ]
69+ libs' = concat [ extraLibs (buildInfo (condTreeData x)) | x <- exeDeps ]
70+
71+simplify :: CondTree ConfVar [Dependency] a -> CondTree ConfVar [Dependency] ()
72+simplify (CondNode _ deps nodes) = CondNode () deps (map simp nodes)
73+ where
74+ simp (cond,tree,mtree) = (cond, simplify tree, maybe Nothing (Just . simplify) mtree)