forked from kazu-yamamoto/cab
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPkgDB.hs
200 lines (163 loc) · 6.33 KB
/
PkgDB.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
{-# LANGUAGE CPP #-}
module PkgDB where
import Control.Applicative
import Control.Monad
import Data.List
import Data.Map (Map)
import qualified Data.Map as M
import Distribution.Compiler
(CompilerId(..))
import Distribution.License
(License(..))
import Distribution.Version
(Version(..))
import Distribution.InstalledPackageInfo
(InstalledPackageInfo_(..), InstalledPackageInfo)
import Distribution.Package
(PackageName(..), PackageIdentifier(..), InstalledPackageId)
import Distribution.Simple.Compiler
(PackageDB(..),Compiler(..))
import Distribution.Simple.GHC
(configure, getInstalledPackages)
import Distribution.Simple.PackageIndex
(lookupPackageName, lookupSourcePackageId, lookupInstalledPackageId
, allPackages, fromList, reverseDependencyClosure
, topologicalOrder, PackageIndex)
import Distribution.Simple.Program.Db
(defaultProgramDb)
import Distribution.Verbosity
(normal)
import System.FilePath
import System.Directory
import Utils
type PkgDB = PackageIndex
type PkgInfo = InstalledPackageInfo
----------------------------------------------------------------
getPkgDB :: Maybe FilePath -> IO PkgDB
getPkgDB mpath = do
(com,pro) <- configure normal Nothing Nothing defaultProgramDb
let userDB = case mpath of
Nothing -> UserPackageDB
Just path -> SpecificPackageDB $ packageConf path com
getInstalledPackages normal [GlobalPackageDB,userDB] pro
getPackageConf :: FilePath -> IO FilePath
getPackageConf path = do
(com,_) <- configure normal Nothing Nothing defaultProgramDb
return $ packageConf path com
packageConf :: FilePath -> Compiler -> FilePath
packageConf path com = path </> "packages-" ++ version ver ++ ".conf"
where
CompilerId _ ver = compilerId com
toPkgDB :: [PkgInfo] -> PkgDB
toPkgDB = fromList
version :: Version -> String
version = toDotted . versionBranch
----------------------------------------------------------------
lookupByName :: String -> PkgDB -> [PkgInfo]
lookupByName name db = concatMap snd $ lookupPackageName db (PackageName name)
lookupByVersion :: String -> String -> PkgDB -> [PkgInfo]
lookupByVersion name ver db = lookupSourcePackageId db src
where
src = PackageIdentifier {
pkgName = PackageName name
, pkgVersion = Version {
versionBranch = fromDotted ver
, versionTags = []
}
}
----------------------------------------------------------------
toPkgList :: (PkgInfo -> Bool) -> PkgDB -> [PkgInfo]
toPkgList prd db = filter prd $ allPackages db
userPkgs :: IO (PkgInfo -> Bool)
userPkgs = do
#ifdef darwin_HOST_OS
-- drop "/."
userDirPref <- takeDirectory <$> getAppUserDataDirectory ""
#else
userDirPref <- getAppUserDataDirectory ""
#endif
return $ \pkgi -> case libraryDirs pkgi of
[] -> False -- haskell-platform for example
xs -> any (userDirPref `isPrefixOf`) xs
allPkgs :: IO (PkgInfo -> Bool)
allPkgs = return (const True)
----------------------------------------------------------------
fullNameOfPkgInfo :: PkgInfo -> String
fullNameOfPkgInfo pkgi = nameOfPkgInfo pkgi ++ " " ++ versionOfPkgInfo pkgi
pairNameOfPkgInfo :: PkgInfo -> (String,String)
pairNameOfPkgInfo pkgi = (nameOfPkgInfo pkgi, versionOfPkgInfo pkgi)
nameOfPkgInfo :: PkgInfo -> String
nameOfPkgInfo = toString . pkgName . sourcePackageId
where
toString (PackageName x) = x
versionOfPkgInfo :: PkgInfo -> String
versionOfPkgInfo = toDotted . numVersionOfPkgInfo
numVersionOfPkgInfo :: PkgInfo -> [Int]
numVersionOfPkgInfo = versionBranch . pkgVersion . sourcePackageId
----------------------------------------------------------------
extraInfo :: Bool -> PkgInfo -> IO ()
extraInfo False _ = return ()
extraInfo True pkgi = putStr $ " " ++ lcns ++ " \"" ++ auth ++ "\""
where
lcns = showLicense (license pkgi)
auth = author pkgi
----------------------------------------------------------------
printDeps :: Bool -> Bool -> PkgDB -> Int -> PkgInfo -> IO ()
printDeps rec info db n pkgi = mapM_ (printDep rec info db n) $ depends pkgi
printDep :: Bool -> Bool -> PkgDB -> Int -> InstalledPackageId -> IO ()
printDep rec info db n pid = case lookupInstalledPackageId db pid of
Nothing -> return ()
Just pkgi -> do
putStr $ prefix ++ fullNameOfPkgInfo pkgi
extraInfo info pkgi
putStrLn ""
when rec $ printDeps rec info db (n+1) pkgi
where
prefix = replicate (n * 4) ' '
showLicense :: License -> String
showLicense (GPL (Just v)) = "GPL" ++ version v
showLicense (GPL Nothing) = "GPL"
showLicense (LGPL (Just v)) = "LGPL" ++ version v
showLicense (LGPL Nothing) = "LGPL"
showLicense (UnknownLicense s) = s
showLicense x = show x
----------------------------------------------------------------
printRevDeps :: Bool -> Bool -> PkgDB -> Int -> PkgInfo -> IO ()
printRevDeps rec info db n pkgi = printRevDeps' rec info db revdb n pkgi
where
revdb = makeRevDepDB db
printRevDeps' :: Bool -> Bool -> PkgDB -> RevDB -> Int -> PkgInfo -> IO ()
printRevDeps' rec info db revdb n pkgi = case M.lookup pkgid revdb of
Nothing -> return ()
Just pkgids -> mapM_ (printRevDep' rec info db revdb n) pkgids
where
pkgid = installedPackageId pkgi
printRevDep' :: Bool -> Bool -> PkgDB -> RevDB -> Int -> InstalledPackageId -> IO ()
printRevDep' rec info db revdb n pid = case lookupInstalledPackageId db pid of
Nothing -> return ()
Just pkgi -> do
putStr $ prefix ++ fullNameOfPkgInfo pkgi
extraInfo info pkgi
putStrLn ""
when rec $ printRevDeps' rec info db revdb (n+1) pkgi
where
prefix = replicate (n * 4) ' '
----------------------------------------------------------------
type RevDB = Map InstalledPackageId [InstalledPackageId]
makeRevDepDB :: PkgDB -> RevDB
makeRevDepDB db = M.fromList revdeps
where
pkgs = allPackages db
deps = map idDeps pkgs
idDeps pkg = (installedPackageId pkg, depends pkg)
kvs = sort $ concatMap decomp deps
decomp (k,vs) = map (\v -> (v,k)) vs
kvss = groupBy (\x y -> fst x == fst y) kvs
comp xs = (fst (head xs), map snd xs)
revdeps = map comp kvss
----------------------------------------------------------------
topSortedPkgs :: PkgInfo -> PkgDB -> [PkgInfo]
topSortedPkgs pkgi db = topSort $ pkgids [pkgi]
where
pkgids = map installedPackageId
topSort = topologicalOrder . fromList . reverseDependencyClosure db