Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 378 lines (326 sloc) 14.318 kB
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
1 module Merge where
2
3 import Control.Monad.Error
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
4 import Control.Exception
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
5 import Data.Char
6 import Data.Maybe
7 import Data.List
8 import Data.Version
9 import Distribution.Package
10 import Distribution.Compiler (CompilerId(..), CompilerFlavor(GHC))
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
11 import Distribution.PackageDescription ( PackageDescription(..)
12 , FlagName(..)
13 , libBuildInfo
14 , buildInfo
1de8047 @kolmodin Add build-tools deps as well, using a static table
kolmodin authored
15 , extraLibs
16 , buildTools )
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
17 import Distribution.PackageDescription.Configuration
18 ( finalizePackageDescription )
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
19 -- import Distribution.PackageDescription.Parse ( showPackageDescription )
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
20 import Distribution.Simple.PackageIndex (PackageIndex)
21 import Distribution.Text (display)
22
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
23 import System.Directory ( getCurrentDirectory
24 , setCurrentDirectory
25 , createDirectoryIfMissing
26 )
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
27 import System.IO
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
28 import System.Cmd (system)
29 import System.FilePath ((</>), splitPath, joinPath, takeFileName)
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
30 import qualified Data.Map as Map
31
32 import qualified Cabal2Ebuild as E
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
33 import Error as E
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
34 import Overlays
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
35
36 import qualified Distribution.Package as Cabal
37 import qualified Distribution.Version as Cabal
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
38
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
39 import Distribution.System (buildOS, buildArch)
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
40 import Distribution.Verbosity
41 import Distribution.Simple.Utils
42
43 import Network.URI
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
44 import Network.HTTP
a1730ad @kolmodin Switch to using Cabal's CLI API
kolmodin authored
45
46 import Cabal2Ebuild
47
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
48 import Distribution.Client.IndexUtils ( getAvailablePackages )
49 import qualified Distribution.Simple.PackageIndex as Index
50 import Distribution.Client.Types
51
52 import qualified Portage.PackageId as Portage
53 import qualified Portage.Version as Portage
54 import qualified Portage.Overlay as Overlay
55
56 import Cabal2Ebuild
57
1c11ba1 @kolmodin Handle colliding package names better when looking for extra-libs
kolmodin authored
58 import Debug.Trace
59
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
60 -- This is just a hack to simplify version ranges.
61 -- Backported from Cabal HEAD to work with Cabal 1.6.
62 -- Replace this module once it's included in a cabal release.
63 import CabalDistributionVersion (simplifyVersionRange)
64
f56d508 @kolmodin Cleanup in merge
kolmodin authored
65 a <-> b = a ++ '-':b
66 a <.> b = a ++ '.':b
67
22e0fbc @kolmodin Add requests for 'hackport merge'
kolmodin authored
68 {-
69 Requested features:
c2b8367 @kolmodin Update TODOs
kolmodin authored
70 * Copy the old keywords and ~arch them
22e0fbc @kolmodin Add requests for 'hackport merge'
kolmodin authored
71 * Add files to darcs?
72 * Print diff with the next latest version?
96a6477 @kolmodin Add some todos
kolmodin authored
73 BUGS:
74 * Dependencies are always expected to be in dev-haskell
22e0fbc @kolmodin Add requests for 'hackport merge'
kolmodin authored
75 -}
76
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
77 readPackageString :: [String]
78 -> Either HackPortError ( Maybe Portage.Category
79 , Cabal.PackageName
80 , Maybe Portage.Version
81 )
82 readPackageString args = do
83 packageString <-
84 case args of
7ab62d5 @kolmodin Tried hlint, nice.
kolmodin authored
85 [] -> Left (ArgumentError "Need an argument, [category/]package[-version]")
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
86 [pkg] -> return pkg
87 _ -> Left (ArgumentError ("Too many arguments: " ++ unwords args))
88 case Portage.parseFriendlyPackage packageString of
89 Just v@(_,_,Nothing) -> return v
90 -- we only allow versions we can convert into cabal versions
91 Just v@(_,_,Just (Portage.Version _ Nothing [] 0)) -> return v
92 _ -> Left (ArgumentError ("Could not parse [category/]package[-version]: " ++ packageString))
93
94 -- | If a package already exist in the overlay, find which category it has.
95 -- If it does not exist, we default to \'dev-haskell\'.
96 resolveCategory :: Verbosity -> Overlay.Overlay -> Cabal.PackageName -> IO Portage.Category
97 resolveCategory verbosity overlay pn = do
7ab62d5 @kolmodin Tried hlint, nice.
kolmodin authored
98 info verbosity "Searching for which category to use..."
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
99 case resolveCategories overlay pn of
100 [] -> do
101 info verbosity "No previous version of this package, defaulting category to dev-haskell."
102 return devhaskell
103 [cat] -> do
104 info verbosity $ "Exact match of already existing package, using category: "
105 ++ display cat
106 return cat
107 cats -> do
108 warn verbosity $ "Multiple matches of categories: " ++ unwords (map display cats)
109 if devhaskell `elem` cats
110 then do notice verbosity "Defaulting to dev-haskell"
111 return devhaskell
112 else do warn verbosity "Multiple matches and no known default. Override by specifying "
113 warn verbosity "package category like so 'hackport merge categoryname/package[-version]."
114 throwEx (ArgumentError "Specify package category and try again.")
115 where
116 devhaskell = Portage.Category "dev-haskell"
117
118 resolveCategories :: Overlay.Overlay -> Cabal.PackageName -> [Portage.Category]
119 resolveCategories overlay pn =
120 [ cat
121 | (Portage.PackageName cat pn') <- Map.keys om
122 , pn == Portage.normalizeCabalPackageName pn'
123 ]
124 where
125 om = Overlay.overlayMap overlay
126
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
127 resolveFullPortageName :: Overlay.Overlay -> Cabal.PackageName -> Maybe Portage.PackageName
128 resolveFullPortageName overlay pn =
129 case resolveCategories overlay pn of
130 [] -> Nothing
1c11ba1 @kolmodin Handle colliding package names better when looking for extra-libs
kolmodin authored
131 [cat] -> ret cat
132 cats | (cat:_) <- (filter (`elem` cats) priority) -> ret cat
133 | otherwise -> trace ("Ambiguous package name: " ++ show pn ++ ", hits: " ++ show cats) Nothing
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
134 where
1c11ba1 @kolmodin Handle colliding package names better when looking for extra-libs
kolmodin authored
135 ret c = return (Portage.PackageName c pn)
136 mkC = Portage.Category
137 devhaskell = mkC "dev-haskell"
138 -- if any of these categories show up in the result list, the match isn't
139 -- ambiguous, pick the first match in the list
140 priority = [ mkC "dev-haskell"
141 , mkC "sys-libs"
142 , mkC "dev-libs"
143 , mkC "x11-libs"
144 , mkC "media-libs"
145 , mkC "net-libs"
146 , mkC "sci-libs"
147 ]
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
148
149
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
150 -- | Given a list of available packages, and maybe a preferred version,
151 -- return the available package with that version. Latest version is chosen
152 -- if no preference.
153 resolveVersion :: [AvailablePackage] -> Maybe Cabal.Version -> Maybe AvailablePackage
154 resolveVersion avails Nothing = Just $ maximumBy (comparing packageInfoId) avails
155 resolveVersion avails (Just ver) = listToMaybe (filter match avails)
156 where
7ab62d5 @kolmodin Tried hlint, nice.
kolmodin authored
157 match avail = ver == pkgVersion (packageInfoId avail)
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
158
159 merge :: Verbosity -> Repo -> URI -> [String] -> IO ()
160 merge verbosity repo serverURI args = do
161 (m_category, user_pName, m_version) <-
162 case readPackageString args of
163 Left err -> throwEx err
164 Right (c,p,m_v) ->
165 case m_v of
166 Nothing -> return (c,p,Nothing)
167 Just v -> case Portage.toCabalVersion v of
168 Nothing -> throwEx (ArgumentError "illegal version")
169 Just ver -> return (c,p,Just ver)
170
171 debug verbosity $ "Category: " ++ show m_category
172 debug verbosity $ "Package: " ++ show user_pName
173 debug verbosity $ "Version: " ++ show m_version
174
175 let (Cabal.PackageName user_pname_str) = user_pName
176
177 overlayPath <- getOverlayPath verbosity
178 overlay <- Overlay.loadLazy overlayPath
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
179 portage <- Overlay.loadLazy "/usr/portage"
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
180 index <- fmap packageIndex $ getAvailablePackages verbosity [ repo ]
181
182 -- find all packages that maches the user specified package name
183 availablePkgs <-
184 case Index.searchByName index user_pname_str of
185 Index.None -> throwEx (PackageNotFound user_pname_str)
186 Index.Ambiguous pkgs -> throwEx (ArgumentError ("Ambiguous name: " ++ unwords (map show pkgs)))
187 Index.Unambiguous pkg -> return pkg
188
189 -- select a single package taking into account the user specified version
190 selectedPkg <-
191 case resolveVersion availablePkgs m_version of
192 Nothing -> do
193 putStrLn "No such version for that package, available versions:"
7ab62d5 @kolmodin Tried hlint, nice.
kolmodin authored
194 forM_ availablePkgs $ \ avail ->
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
195 putStrLn (display . packageInfoId $ avail)
196 throwEx (ArgumentError "no such version for that package")
197 Just avail -> return avail
198
199 -- print some info
200 info verbosity "Selecting package:"
201 forM_ availablePkgs $ \ avail -> do
202 let match_text | packageInfoId avail == packageInfoId selectedPkg = "* "
203 | otherwise = "- "
204 info verbosity $ match_text ++ (display . packageInfoId $ avail)
205
206 let cabal_pkgId = packageInfoId selectedPkg
207 cabal_pkgName = packageName cabal_pkgId
208 pkgVer = packageVersion cabal_pkgId
209 norm_pkgId = Portage.normalizeCabalPackageId cabal_pkgId
210 norm_pkgName = packageName norm_pkgId
211 category <- resolveCategory verbosity overlay norm_pkgName
212
213 let pkgGenericDesc = packageDescription selectedPkg
214 Right (pkgDesc0, flags) =
215 finalizePackageDescription
216 [ -- XXX: common things we should enable/disable?
217 -- (FlagName "small_base", True) -- try to use small base
218 ]
219 (Nothing :: Maybe (PackageIndex PackageIdentifier))
220 buildOS buildArch
221 (CompilerId GHC (Version [6,10,1] []))
222 [] pkgGenericDesc
223 pkgDesc = let deps = [ Dependency pn (simplifyVersionRange vr)
224 | Dependency pn vr <- buildDepends pkgDesc0
225 ]
226 in pkgDesc0 { buildDepends = deps }
1de8047 @kolmodin Add build-tools deps as well, using a static table
kolmodin authored
227
228 bt = [ Cabal.Dependency (Cabal.PackageName pkg') range
229 | Cabal.Dependency (Cabal.PackageName pkg ) range <- buildToolsDeps pkgDesc
230 , Just pkg' <- return (lookup pkg buildToolsTable)
231 ]
232
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
233 packageNameResolver s = do
234 (Portage.PackageName (Portage.Category cat) (Cabal.PackageName pn))
235 <- resolveFullPortageName portage (Cabal.PackageName s)
36431fe @kolmodin Further cleanup
kolmodin authored
236 return $ E.AnyVersionOf (cat </> pn)
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
237
238 extra <- findCLibs verbosity packageNameResolver pkgDesc
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
239
240 debug verbosity ("Selected flags: " ++ show flags)
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
241 debug verbosity ("extra-libs: ")
242 mapM_ (debug verbosity . show) extra
1de8047 @kolmodin Add build-tools deps as well, using a static table
kolmodin authored
243
244 debug verbosity ("build-tools:")
245 mapM_ (debug verbosity . show) bt
246
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
247 -- debug verbosity ("Finalized package:\n" ++ showPackageDescription pkgDesc)
248
249 -- TODO: more fixes
96a6477 @kolmodin Add some todos
kolmodin authored
250 -- * inherit keywords from previous ebuilds
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
251 let ebuild = fixSrc serverURI (packageId pkgDesc)
252 . addDeps extra
1de8047 @kolmodin Add build-tools deps as well, using a static table
kolmodin authored
253 . addDeps (convertDependencies bt)
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
254 $ E.cabal2ebuild pkgDesc
96a6477 @kolmodin Add some todos
kolmodin authored
255 ebuildName = display category </> display norm_pkgId
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
256
257 mergeEbuild verbosity overlayPath (Portage.unCategory category) ebuild
258 fetchAndDigest
259 verbosity
260 (overlayPath </> display category </> display norm_pkgName)
261 (display cabal_pkgId <.> "tar.gz")
262 (mkUri cabal_pkgId)
263
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
264 addDeps :: [E.Dependency] -> EBuild -> EBuild
265 addDeps d e = e { depend = depend e ++ d }
266
36431fe @kolmodin Further cleanup
kolmodin authored
267 findCLibs :: Verbosity -> (String -> Maybe E.Dependency) -> PackageDescription -> IO [E.Dependency]
268 findCLibs verbosity portageResolver (PackageDescription { library = lib, executables = exes }) = do
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
269 debug verbosity "Mapping extra-libraries into portage packages..."
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
270 -- for extra libs we don't find, maybe look into into installed packages?
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
271 when (not . null $ notFound) $
87489f1 @kolmodin Clean up the extra-libraries resolving a bit
kolmodin authored
272 warn verbosity ("Could not find portage packages for extra-libraries: " ++ unwords notFound)
823b6ef @kolmodin Look into portage dir when resolving extra-libraries
kolmodin authored
273 when (not . null $ found) $
274 debug verbosity ("Found c-libraries deps: " ++ show found)
275 return found
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
276 where
87489f1 @kolmodin Clean up the extra-libraries resolving a bit
kolmodin authored
277 resolvers = [ staticTranslateExtraLib, portageResolver ]
278
279 resolved = [ chain p resolvers
280 | p <- libE ++ exeE
281 ] :: [Either String E.Dependency]
282
283 notFound = [ p | Left p <- resolved ]
284 found = [ p | Right p <- resolved ]
285
286 chain v [] = Left v
287 chain v (f:fs) = case f v of
288 Nothing -> chain v fs
289 Just x -> Right x
290
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
291 libE = maybe [] (extraLibs.libBuildInfo) lib
292 exeE = concatMap (extraLibs.buildInfo) exes
293
87489f1 @kolmodin Clean up the extra-libraries resolving a bit
kolmodin authored
294 staticTranslateExtraLib :: String -> Maybe E.Dependency
295 staticTranslateExtraLib lib = lookup lib m
cb4a7bb @kolmodin Start on translating extra-libraries into ebuild deps
kolmodin authored
296 where
297 m = [ ("z", E.AnyVersionOf "sys-libs/zlib")
298 , ("bz2", E.AnyVersionOf "sys-libs/bzlib")
299 ]
300
1de8047 @kolmodin Add build-tools deps as well, using a static table
kolmodin authored
301 buildToolsDeps :: PackageDescription -> [Cabal.Dependency]
302 buildToolsDeps (PackageDescription { library = lib, executables = exes }) = cabalDeps
303 where
304 cabalDeps = depL ++ depE
305 depL = maybe [] (buildTools.libBuildInfo) lib
306 depE = concatMap (buildTools.buildInfo) exes
307
308 buildToolsTable :: [(String, String)]
309 buildToolsTable =
310 [ ("happy", "dev-haskell/happy")
311 , ("alex", "dev-haskell/alex")
312 , ("c2hs", "dev-haskell/c2hs")
313 ]
314
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
315 mkUri :: Cabal.PackageIdentifier -> URI
316 mkUri pid =
317 -- example:
318 -- http://hackage.haskell.org/packages/archive/Cabal/1.4.0.2/Cabal-1.4.0.2.tar.gz
319 fromJust $ parseURI $
320 "http://hackage.haskell.org/packages/archive/"
321 </> name </> ver </> name <-> ver <.> "tar.gz"
322 where
323 ver = display (packageVersion pid)
324 name = display (packageName pid)
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
325
326 fetchAndDigest :: Verbosity
327 -> FilePath -- ^ directory of ebuild
328 -> String -- ^ tarball name
329 -> URI -- ^ tarball uri
6ec3592 Hackport now uses Cabal-1.6
Ivan.Miljenovic@gmail.com authored
330 -> IO ()
7ab62d5 @kolmodin Tried hlint, nice.
kolmodin authored
331 fetchAndDigest verbosity ebuildDir tarballName tarballURI =
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
332 withWorkingDirectory ebuildDir $ do
f56d508 @kolmodin Cleanup in merge
kolmodin authored
333 notice verbosity $ "Fetching " ++ show tarballURI
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
334 response <- simpleHTTP (Request tarballURI GET [] "")
335 case response of
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
336 Left err -> throwEx (E.DownloadFailed (show tarballURI) (show err))
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
337 Right response -> do
338 let tarDestination = "/usr/portage/distfiles" </> tarballName
f56d508 @kolmodin Cleanup in merge
kolmodin authored
339 notice verbosity $ "Saving to " ++ tarDestination
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
340 writeFile tarDestination (rspBody response)
7ab62d5 @kolmodin Tried hlint, nice.
kolmodin authored
341 notice verbosity "Recalculating digests..."
8135c0c @kolmodin Implement fetching and creation of digests for new ebuilds
kolmodin authored
342 system "repoman manifest"
343 return ()
344
345 withWorkingDirectory :: FilePath -> IO a -> IO a
346 withWorkingDirectory newDir action = do
347 oldDir <- getCurrentDirectory
348 bracket
349 (setCurrentDirectory newDir)
350 (\_ -> setCurrentDirectory oldDir)
351 (\_ -> action)
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
352
353 mergeEbuild :: Verbosity -> FilePath -> String -> EBuild -> IO ()
354 mergeEbuild verbosity target category ebuild = do
355 let edir = target </> category </> name ebuild
356 elocal = name ebuild ++"-"++ version ebuild <.> "ebuild"
357 epath = edir </> elocal
358 createDirectoryIfMissing True edir
359 info verbosity $ "Writing " ++ elocal
360 writeFile epath (showEBuild ebuild)
361
362 fixSrc :: URI -> PackageIdentifier -> EBuild -> EBuild
363 fixSrc serverURI p ebuild =
364 ebuild {
365 src_uri = show $ serverURI {
366 uriPath =
7ab62d5 @kolmodin Tried hlint, nice.
kolmodin authored
367 uriPath serverURI
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
368 </> display (pkgName p)
369 </> display (pkgVersion p)
370 </> display (pkgName p) ++ "-" ++ display (pkgVersion p)
371 <.> "tar.gz"
175e753 @kolmodin Set a default homepage to hackport if none is set
kolmodin authored
372 },
373 E.homepage = case E.homepage ebuild of
374 "" -> "http://hackage.haskell.org/cgi-bin/hackage-scripts/package/"
375 ++ display (pkgName p)
376 x -> x
f309365 @kolmodin Reimplement 'hackport merge'
kolmodin authored
377 }
Something went wrong with that request. Please try again.