Skip to content

HTTPS clone URL

Subversion checkout URL

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