Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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