@@ -17,7 +17,7 @@ import Text.ParserCombinators.ReadP ( readP_to_S )
17import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )
17import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )
18import Distribution.PackageDescription ( GenericPackageDescription() )
18import Distribution.PackageDescription ( GenericPackageDescription() )
19import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )
19import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )
20−import Cabal2Nix.Package ( cabal2nix, showNixPkg, PkgName, PkgSHA256, PkgPlatforms, PkgMaintainers, PkgNoHaddock )
20+import Cabal2Nix.Package ( cabal2nix, showNixPkg, PkgName, PkgVersion, PkgSHA256, PkgPlatforms, PkgMaintainers, PkgNoHaddock )
22type PkgSet = Set.Set Pkg
22type PkgSet = Set.Set Pkg
@@ -62,24 +62,17 @@ readCabalFile name vers = do
63discoverNixFiles :: (FilePath -> Hackage4Nix ()) -> FilePath -> Hackage4Nix ()
63discoverNixFiles :: (FilePath -> Hackage4Nix ()) -> FilePath -> Hackage4Nix ()
64discoverNixFiles yield dirOrFile
64discoverNixFiles yield dirOrFile
65− | "." `isPrefixOf` takeFileName dirOrFile = msgDebug $ "ignore file or directory " ++ dirOrFile
65+ | "." `isPrefixOf` takeFileName dirOrFile = return ()
66 | otherwise = do
66 | otherwise = do
67 isFile <- io (doesFileExist dirOrFile)
67 isFile <- io (doesFileExist dirOrFile)
68 case (isFile, takeExtension dirOrFile) of
68 case (isFile, takeExtension dirOrFile) of
70− msgDebug ("discovered file " ++ dirOrFile)
71− yield dirOrFile
69+ (True,".nix") -> yield dirOrFile
72− (True,_) -> msgDebug $ "ignore file " ++ dirOrFile
70+ (True,_) -> return ()
74− msgDebug ("discovered dir " ++ dirOrFile)
75− io (readDirectory dirOrFile) >>= mapM_ (discoverNixFiles yield . (dirOrFile </>))
71+ (False,_) -> io (readDirectory dirOrFile) >>= mapM_ (discoverNixFiles yield . (dirOrFile </>))
77−type PkgVersion = String
78−data Pkg = Pkg PkgName PkgVersion PkgSHA256 PkgNoHaddock PkgPlatforms PkgMaintainers FilePath
79− deriving (Show, Eq, Ord)
81−regmatch :: String -> String -> Bool
73+type Regenerate = Bool
82−regmatch buf patt = match (makeRegexOpts compExtended execBlank patt) buf
74+data Pkg = Pkg PkgName PkgVersion PkgSHA256 PkgNoHaddock PkgPlatforms PkgMaintainers FilePath Regenerate
75+ deriving (Show, Eq, Ord)
84regsubmatch :: String -> String -> [String]
77regsubmatch :: String -> String -> [String]
85regsubmatch buf patt = let (_,_,_,x) = f in x
78regsubmatch buf patt = let (_,_,_,x) = f in x
@@ -93,16 +86,13 @@ normalizeMaintainer x
94parseNixFile :: FilePath -> String -> Hackage4Nix (Maybe Pkg)
87parseNixFile :: FilePath -> String -> Hackage4Nix (Maybe Pkg)
95parseNixFile path buf
88parseNixFile path buf
96− | not (buf `regmatch` "cabal.mkDerivation")
89+ | not (buf =~ "cabal.mkDerivation")
97 = msgDebug ("ignore non-cabal package " ++ path) >> return Nothing
90 = msgDebug ("ignore non-cabal package " ++ path) >> return Nothing
98− | True <- path `regmatch` (concat (intersperse "|" badPackages))
91+ | any (`isSuffixOf`path) badPackagePaths
99 = msgDebug ("ignore known bad package " ++ path) >> return Nothing
92 = msgDebug ("ignore known bad package " ++ path) >> return Nothing
100− | True <- buf `regmatch` "src = (fetchgit|sourceFromHead)"
93+ | buf =~ "src = (fetchurl|fetchgit|sourceFromHead)"
101 = msgDebug ("ignore non-hackage package " ++ path) >> return Nothing
94 = msgDebug ("ignore non-hackage package " ++ path) >> return Nothing
102− | buf `regmatch` "preConfigure|configureFlags|postInstall|patchPhase"
103− = msgInfo ("ignore patched package " ++ path) >> return Nothing
104− | True <- buf =~ "cabal.mkDerivation"
105− , [name] <- buf `regsubmatch` "name *= *\"([^\"]+)\""
95+ | [name] <- buf `regsubmatch` "name *= *\"([^\"]+)\""
106 , [vers] <- buf `regsubmatch` "version *= *\"([^\"]+)\""
96 , [vers] <- buf `regsubmatch` "version *= *\"([^\"]+)\""
107 , [sha] <- buf `regsubmatch` "sha256 *= *\"([^\"]+)\""
97 , [sha] <- buf `regsubmatch` "sha256 *= *\"([^\"]+)\""
108 , plats <- buf `regsubmatch` "platforms *= *([^;]+);"
98 , plats <- buf `regsubmatch` "platforms *= *([^;]+);"
@@ -113,17 +103,13 @@ parseNixFile path buf
113 noHaddock
103 noHaddock
114 | "true":[] <- haddock = True
104 | "true":[] <- haddock = True
115 | otherwise = False
105 | otherwise = False
106+ regenerate = not (name `elem` patchedPackages) &&
107+ not (buf =~ "preConfigure|configureFlags|postInstall|patchPhase")
117− return $ Just $ Pkg name
109+ return $ Just $ Pkg name vers sha noHaddock plats'
122 (map normalizeMaintainer maint')
110 (map normalizeMaintainer maint')
123− path
111+ path regenerate
124− | True <- buf `regmatch` "cabal.mkDerivation"
125− = msgInfo ("failed to parse file " ++ path) >> return Nothing
112+ | otherwise = msgInfo ("failed to parse file " ++ path) >> return Nothing
126− | otherwise = return Nothing
128readVersion :: String -> Version
114readVersion :: String -> Version
129readVersion str =
115readVersion str =
@@ -134,10 +120,10 @@ readVersion str =
134selectLatestVersions :: PkgSet -> PkgSet
120selectLatestVersions :: PkgSet -> PkgSet
135selectLatestVersions = Set.fromList . nubBy f2 . sortBy f1 . Set.toList
121selectLatestVersions = Set.fromList . nubBy f2 . sortBy f1 . Set.toList
137− f1 (Pkg n1 v1 _ _ _ _ _) (Pkg n2 v2 _ _ _ _ _)
123+ f1 (Pkg n1 v1 _ _ _ _ _ _) (Pkg n2 v2 _ _ _ _ _ _)
138 | n1 == n2 = compare v2 v1
124 | n1 == n2 = compare v2 v1
139 | otherwise = compare n1 n2
125 | otherwise = compare n1 n2
140− f2 (Pkg n1 _ _ _ _ _ _) (Pkg n2 _ _ _ _ _ _)
126+ f2 (Pkg n1 _ _ _ _ _ _ _) (Pkg n2 _ _ _ _ _ _ _)
141 = n1 == n2
127 = n1 == n2
143discoverUpdates :: PkgName -> PkgVersion -> Hackage4Nix [PkgVersion]
129discoverUpdates :: PkgName -> PkgVersion -> Hackage4Nix [PkgVersion]
@@ -145,7 +131,7 @@ discoverUpdates name vers = do
145 hackage <- gets _hackageDb
131 hackage <- gets _hackageDb
146 versionStrings <- io $ readDirectory (hackage </> name)
132 versionStrings <- io $ readDirectory (hackage </> name)
147 let versions = map readVersion versionStrings
133 let versions = map readVersion versionStrings
148− return [ showVersion v | v <- versions, v > readVersion vers ]
134+ return (sort [ showVersion v | v <- versions, v > readVersion vers ])
150updateNixPkgs :: [FilePath] -> Hackage4Nix ()
136updateNixPkgs :: [FilePath] -> Hackage4Nix ()
151updateNixPkgs paths = do
137updateNixPkgs paths = do
@@ -154,44 +140,45 @@ updateNixPkgs paths = do
154 flip discoverNixFiles fileOrDir $ \file -> do
140 flip discoverNixFiles fileOrDir $ \file -> do
155 nix' <- io (readFile file) >>= parseNixFile file
141 nix' <- io (readFile file) >>= parseNixFile file
156 flip (maybe (return ())) nix' $ \nix -> do
142 flip (maybe (return ())) nix' $ \nix -> do
157− let Pkg name vers sha noHaddock plats maints path = nix
143+ let Pkg name vers sha noHaddock plats maints path regenerate = nix
158− maints' = nub (sort (maints ++ ["andres","simons"]))
160− | null plats && not (null maints) = ["self.ghc.meta.platforms"]
162− msgDebug ("re-generate " ++ path)
163− when (null maints) (msgInfo ("no maintainers configured for " ++ path))
164− pkg <- readCabalFile name vers
165− io $ writeFile path (showNixPkg (cabal2nix pkg sha noHaddock plats' maints'))
166 modify $ \cfg -> cfg { _pkgset = Set.insert nix (_pkgset cfg) }
144 modify $ \cfg -> cfg { _pkgset = Set.insert nix (_pkgset cfg) }
145+ when regenerate $ do
146+ msgDebug ("re-generate " ++ path)
147+ let maints' = nub (sort (maints ++ ["andres","simons"]))
149+ | null plats && not (null maints) = ["self.ghc.meta.platforms"]
151+ when (null maints) (msgInfo ("no maintainers configured for " ++ path))
152+ pkg <- readCabalFile name vers
153+ io $ writeFile path (showNixPkg (cabal2nix pkg sha noHaddock plats' maints'))
167 pkgset <- gets (selectLatestVersions . _pkgset)
154 pkgset <- gets (selectLatestVersions . _pkgset)
168 updates' <- flip mapM (Set.elems pkgset) $ \pkg -> do
155 updates' <- flip mapM (Set.elems pkgset) $ \pkg -> do
169− let Pkg name vers _ _ _ _ _ = pkg
156+ let Pkg name vers _ _ _ _ _ _ = pkg
170 updates <- discoverUpdates name vers
157 updates <- discoverUpdates name vers
171 return (pkg,updates)
158 return (pkg,updates)
172 let updates = [ u | u@(_,(_:_)) <- updates' ]
159 let updates = [ u | u@(_,(_:_)) <- updates' ]
173 when (not (null updates)) $ do
160 when (not (null updates)) $ do
174 msgInfo "The following updates are available:"
161 msgInfo "The following updates are available:"
175 flip mapM_ updates $ \(pkg,versions) -> do
162 flip mapM_ updates $ \(pkg,versions) -> do
176− let Pkg name vers _ noHaddock plats maints path = pkg
163+ let Pkg name vers _ noHaddock plats maints path regenerate = pkg
177 msgInfo ""
164 msgInfo ""
178 msgInfo $ name ++ "-" ++ vers ++ ":"
165 msgInfo $ name ++ "-" ++ vers ++ ":"
179 flip mapM_ versions $ \newVersion -> do
166 flip mapM_ versions $ \newVersion -> do
180− msgInfo $ " " ++ genCabal2NixCmdline (Pkg name newVersion undefined noHaddock plats maints path)
167+ msgInfo $ " " ++ genCabal2NixCmdline (Pkg name newVersion undefined noHaddock plats maints path regenerate)
181 return ()
168 return ()
183genCabal2NixCmdline :: Pkg -> String
170genCabal2NixCmdline :: Pkg -> String
184−genCabal2NixCmdline (Pkg name vers _ noHaddock plats maints path) = unwords $ ["cabal2nix"] ++ opts ++ [">"++path']
171+genCabal2NixCmdline (Pkg name vers _ noHaddock plats maints path _) = unwords $ ["cabal2nix"] ++ opts ++ [">"++path']
186 opts = [cabal] ++ maints' ++ plats' ++ if noHaddock then ["--no-haddock"] else []
173 opts = [cabal] ++ maints' ++ plats' ++ if noHaddock then ["--no-haddock"] else []
187 cabal = "cabal://" ++ name ++ "-" ++ vers
174 cabal = "cabal://" ++ name ++ "-" ++ vers
188 maints' = [ "--maintainer=" ++ m | m <- maints ]
175 maints' = [ "--maintainer=" ++ m | m <- maints ]
190− | ["self.ghc.meta.platforms"] == plats = []
177+ | ["self.ghc.meta.platforms"] == plats = []
191− | otherwise = [ "--platform=" ++ p | p <- plats ]
178+ | otherwise = [ "--platform=" ++ p | p <- plats ]
193− | path `regmatch` "/[0-9\\.]+\\.nix$" = replaceFileName path (vers <.> "nix")
180+ | path =~ "/[0-9\\.]+\\.nix$" = replaceFileName path (vers <.> "nix")
194− | otherwise = path
181+ | otherwise = path
196data CliOption = PrintHelp | Verbose | HackageDB FilePath
183data CliOption = PrintHelp | Verbose | HackageDB FilePath
197 deriving (Eq)
184 deriving (Eq)
@@ -240,50 +227,48 @@ main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
240 flip evalStateT cfg (updateNixPkgs args)
227 flip evalStateT cfg (updateNixPkgs args)
230+-- Packages that we cannot parse.
232+badPackagePaths :: [FilePath]
233+badPackagePaths = ["haskell-platform/2011.2.0.1.nix"]
244-- Packages that we cannot regenerate automatically yet. This list
235-- Packages that we cannot regenerate automatically yet. This list
245-- should be empty.
236-- should be empty.
247−badPackages :: [String]
238+patchedPackages :: [String]
248−badPackages = [ "/"++p++"/" | p <- names ]
239+patchedPackages =
250− [ "alex" -- undeclared dependencies
240+ [ "alex" -- undeclared dependencies
251− , "CS173Tourney" -- parser error
252− , "get-options" -- parser error
253− , "WebServer" -- these two are not on Hackage
254− , "WebServer-Extras"
255− , "cairo" -- undeclared dependencies
241+ , "cairo" -- undeclared dependencies
256− , "citeproc-hs" -- undeclared dependencies
242+ , "citeproc-hs" -- undeclared dependencies
257− , "editline" -- undeclared dependencies
243+ , "editline" -- undeclared dependencies
258− , "flapjax" -- parser error
259− , "glade" -- undeclared dependencies
244+ , "glade" -- undeclared dependencies
260− , "glib" -- undeclared dependencies
245+ , "glib" -- undeclared dependencies
261− , "epic" -- undeclared dependencies
246+ , "epic" -- undeclared dependencies
262− , "GLUT" -- undeclared dependencies
247+ , "GLUT" -- undeclared dependencies
263− , "gtk" -- undeclared dependencies
248+ , "gtk" -- undeclared dependencies
264− , "gtksourceview2" -- undeclared dependencies
249+ , "gtksourceview2" -- undeclared dependencies
265− , "haddock" -- undeclared dependencies
250+ , "haddock" -- undeclared dependencies
266− , "haskell-platform" -- not on Hackage
267− , "haskell-src" -- undeclared dependencies
251+ , "haskell-src" -- undeclared dependencies
268− , "hmatrix" -- undeclared dependencies
252+ , "hmatrix" -- undeclared dependencies
269− , "hp2any-graph" -- undeclared dependencies
253+ , "hp2any-graph" -- undeclared dependencies
270− , "lhs2tex" -- undeclared dependencies
254+ , "lhs2tex" -- undeclared dependencies
271− , "OpenAL" -- undeclared dependencies
255+ , "OpenAL" -- undeclared dependencies
272− , "OpenGL" -- undeclared dependencies
256+ , "OpenGL" -- undeclared dependencies
273− , "pango" -- undeclared dependencies
257+ , "pango" -- undeclared dependencies
274− , "idris" -- undeclared dependencies
258+ , "idris" -- undeclared dependencies
275− , "readline" -- undeclared dependencies
259+ , "readline" -- undeclared dependencies
276− , "repa-examples" -- undeclared dependencies
260+ , "repa-examples" -- undeclared dependencies
277− , "scion" -- expects non-existent networkBytestring
261+ , "scion" -- expects non-existent networkBytestring
278− , "SDL" -- undeclared dependencies
262+ , "SDL" -- undeclared dependencies
279− , "SDL-image" -- undeclared dependencies
263+ , "SDL-image" -- undeclared dependencies
280− , "SDL-mixer" -- undeclared dependencies
264+ , "SDL-mixer" -- undeclared dependencies
281− , "SDL-ttf" -- undeclared dependencies
265+ , "SDL-ttf" -- undeclared dependencies
282− , "svgcairo" -- undeclared dependencies
266+ , "svgcairo" -- undeclared dependencies
283− , "terminfo" -- undeclared dependencies
267+ , "terminfo" -- undeclared dependencies
284− , "xmonad" -- undeclared dependencies
268+ , "xmonad" -- undeclared dependencies
269+ , "xmonad-extras" -- undeclared dependencies
285− , "vacuum" -- undeclared dependencies
270+ , "vacuum" -- undeclared dependencies
286− , "wxHaskell" -- undeclared dependencies
271+ , "wxcore" -- undeclared dependencies
287− , "X11"
272+ , "X11" -- undeclared dependencies
288− , "X11-xft"
273+ , "X11-xft" -- undeclared dependencies