Last active
December 24, 2016 04:02
-
-
Save tfausak/98726c8255c5bc5c940e0f4939978a43 to your computer and use it in GitHub Desktop.
Gets the package index from Hackage and outputs a bunch of information about their version numbers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- stack | |
--resolver lts-7 | |
--install-ghc | |
runghc | |
--package containers | |
--package filepath | |
--package http-client | |
--package http-client-tls | |
--package tar | |
--package time | |
--package zlib | |
-- | |
-Wall | |
-} | |
{-# LANGUAGE OverloadedStrings #-} | |
import Data.Function ((&)) | |
import qualified Codec.Archive.Tar as Tar | |
import qualified Codec.Compression.GZip as GZip | |
import qualified Control.Monad as Monad | |
import qualified Data.List as List | |
import qualified Data.Map as Map | |
import qualified Data.Maybe as Maybe | |
import qualified Data.Ord as Ord | |
import qualified Data.Set as Set | |
import qualified Data.Time as Time | |
import qualified Data.Tuple as Tuple | |
import qualified Data.Version as Version | |
import qualified Network.HTTP.Client as Client | |
import qualified Network.HTTP.Client.TLS as TLS | |
import qualified System.FilePath as FilePath | |
import qualified Text.ParserCombinators.ReadP as ReadP | |
main :: IO () | |
main = do | |
now <- Time.getCurrentTime | |
print now | |
putStrLn "Getting package index ..." | |
let url = "https://hackage.haskell.org/packages/index.tar.gz" | |
request <- Client.parseUrlThrow url | |
manager <- Client.newManager TLS.tlsManagerSettings | |
response <- Client.httpLbs request manager | |
putStrLn "Got package index." | |
let body = Client.responseBody response | |
let archive = GZip.decompress body | |
let entries = Tar.read archive | |
let packages = Tar.foldEntries update Map.empty (const Map.empty) entries | |
putStrLn ("Found " ++ pluralize (Map.size packages) "package" ++ ".") | |
putStrLn "" | |
let components = | |
packages & Map.map (Set.map Version.versionBranch) & | |
Map.map Set.toAscList & | |
Map.map (map length) & | |
Map.mapMaybe mode | |
putStrLn ("Number of version components => number of packages") | |
components & toMapOfSets & Map.map Set.size & showMap & putStrLn | |
let majors = | |
packages & Map.map (Set.map Version.versionBranch) & | |
Map.map Set.toAscList & | |
Map.map (Maybe.mapMaybe Maybe.listToMaybe) & | |
Map.map List.group & | |
Map.map length | |
putStrLn ("Number of major versions => number of packages") | |
majors & toMapOfSets & Map.map Set.size & showMap & putStrLn | |
let componentMajors = | |
components & | |
Map.mapMaybeWithKey | |
(\k v -> do | |
x <- Map.lookup k majors | |
pure (v, x)) | |
putStrLn | |
("Number of (version components, major versions) => number of packages") | |
componentMajors & toMapOfSets & Map.map Set.size & showMap & putStrLn | |
let current = | |
packages & Map.mapMaybe Set.maxView & Map.map fst & | |
Map.map Version.versionBranch & | |
Map.mapMaybe Maybe.listToMaybe | |
putStrLn ("Current major version => number of packages") | |
current & toMapOfSets & Map.map Set.size & showMap & putStrLn | |
let componentCurrent = | |
components & | |
Map.mapMaybeWithKey | |
(\k v -> do | |
x <- Map.lookup k current | |
pure (v, x)) | |
putStrLn | |
("(Number of version components, current major version) => number of packages") | |
componentCurrent & toMapOfSets & Map.map Set.size & showMap & putStrLn | |
let releases = packages & Map.map Set.size | |
putStrLn ("Number of releases => number of packages") | |
releases & toMapOfSets & Map.map Set.size & showMap & putStrLn | |
type Package = String | |
type Versions = Set.Set Version.Version | |
update :: Tar.Entry -> Map.Map Package Versions -> Map.Map Package Versions | |
update entry x = | |
case getMetadata entry of | |
Nothing -> x | |
Just (package, version) -> | |
Map.insertWith Set.union package (Set.singleton version) x | |
getMetadata :: Tar.Entry -> Maybe (Package, Version.Version) | |
getMetadata entry = do | |
Monad.guard (isNormalFile entry) | |
let path = Tar.entryPath entry | |
Monad.guard (isCabalFile path) | |
(package, rawVersion) <- | |
case FilePath.splitPath path of | |
[package, version, _] -> Just (safeInit package, safeInit version) | |
_ -> Nothing | |
version <- readVersion rawVersion | |
Just (package, version) | |
isNormalFile :: Tar.Entry -> Bool | |
isNormalFile entry = | |
case Tar.entryContent entry of | |
Tar.NormalFile _ _ -> True | |
_ -> False | |
isCabalFile :: FilePath -> Bool | |
isCabalFile path = | |
case FilePath.takeExtension path of | |
".cabal" -> True | |
_ -> False | |
safeInit :: [a] -> [a] | |
safeInit x = | |
case x of | |
[] -> [] | |
_ -> init x | |
readVersion :: String -> Maybe Version.Version | |
readVersion x = do | |
let parses = ReadP.readP_to_S Version.parseVersion x | |
parse <- safeLast parses | |
case parse of | |
(version, "") -> Just version | |
_ -> Nothing | |
safeLast :: [a] -> Maybe a | |
safeLast x = | |
case x of | |
[] -> Nothing | |
_ -> Just (last x) | |
pluralize :: Int -> String -> String | |
pluralize count singular = | |
let plural = singular ++ "s" | |
word = | |
case count of | |
1 -> singular | |
_ -> plural | |
in unwords [show count, word] | |
mode | |
:: Ord a | |
=> [a] -> Maybe a | |
mode xs = | |
xs & List.sort & List.group & map (\x -> (length x, x)) & | |
List.sortBy (Ord.comparing Ord.Down) & | |
map snd & | |
Maybe.mapMaybe Maybe.listToMaybe & | |
Maybe.listToMaybe | |
toMapOfSets | |
:: (Ord k, Ord v) | |
=> Map.Map k v -> Map.Map v (Set.Set k) | |
toMapOfSets x = | |
x & Map.toAscList & map Tuple.swap & map (\(k, v) -> (k, Set.singleton v)) & | |
Map.fromListWith Set.union | |
showMap | |
:: (Show k, Show v) | |
=> Map.Map k v -> String | |
showMap x = | |
x & Map.toAscList & map (\(k, v) -> show k ++ " => " ++ show v) & unlines |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2016-12-21 20:45:29.808761 UTC | |
Getting package index ... | |
Got package index. | |
Found 10644 packages. | |
Number of version components => number of packages | |
1 => 21 | |
2 => 1715 | |
3 => 4256 | |
4 => 4639 | |
5 => 9 | |
6 => 2 | |
8 => 2 | |
Number of major versions => number of packages | |
1 => 9723 | |
2 => 685 | |
3 => 142 | |
4 => 60 | |
5 => 17 | |
6 => 12 | |
7 => 2 | |
8 => 2 | |
9 => 1 | |
Number of (version components, major versions) => number of packages | |
(1,1) => 15 | |
(1,2) => 4 | |
(1,4) => 2 | |
(2,1) => 1589 | |
(2,2) => 87 | |
(2,3) => 21 | |
(2,4) => 10 | |
(2,5) => 5 | |
(2,6) => 3 | |
(3,1) => 3748 | |
(3,2) => 367 | |
(3,3) => 81 | |
(3,4) => 35 | |
(3,5) => 11 | |
(3,6) => 9 | |
(3,7) => 2 | |
(3,8) => 2 | |
(3,9) => 1 | |
(4,1) => 4358 | |
(4,2) => 227 | |
(4,3) => 40 | |
(4,4) => 13 | |
(4,5) => 1 | |
(5,1) => 9 | |
(6,1) => 2 | |
(8,1) => 2 | |
Current major version => number of packages | |
0 => 8585 | |
1 => 1412 | |
2 => 270 | |
3 => 130 | |
4 => 55 | |
5 => 39 | |
6 => 10 | |
7 => 16 | |
8 => 6 | |
9 => 15 | |
10 => 2 | |
1000 => 1 | |
2007 => 1 | |
2008 => 8 | |
2009 => 17 | |
2010 => 17 | |
2011 => 10 | |
2012 => 5 | |
2013 => 3 | |
2014 => 8 | |
2015 => 7 | |
2016 => 3 | |
2017 => 1 | |
2999 => 1 | |
3000 => 11 | |
3001 => 2 | |
4000 => 1 | |
7373 => 1 | |
10000 => 1 | |
15320 => 1 | |
15321 => 1 | |
15329 => 1 | |
15778 => 1 | |
17072 => 1 | |
20090215 => 1 | |
(Number of version components, current major version) => number of packages | |
(1,0) => 9 | |
(1,1) => 6 | |
(1,2) => 2 | |
(1,3) => 1 | |
(1,2013) => 1 | |
(1,2016) => 1 | |
(1,2017) => 1 | |
(2,0) => 1332 | |
(2,1) => 289 | |
(2,2) => 46 | |
(2,3) => 20 | |
(2,4) => 11 | |
(2,5) => 5 | |
(2,6) => 2 | |
(2,7) => 1 | |
(2,9) => 1 | |
(2,10) => 1 | |
(2,1000) => 1 | |
(2,15320) => 1 | |
(2,15321) => 1 | |
(2,15329) => 1 | |
(2,15778) => 1 | |
(2,17072) => 1 | |
(2,20090215) => 1 | |
(3,0) => 3199 | |
(3,1) => 701 | |
(3,2) => 130 | |
(3,3) => 59 | |
(3,4) => 25 | |
(3,5) => 27 | |
(3,6) => 7 | |
(3,7) => 15 | |
(3,8) => 5 | |
(3,9) => 11 | |
(3,2007) => 1 | |
(3,2008) => 8 | |
(3,2009) => 16 | |
(3,2010) => 14 | |
(3,2011) => 6 | |
(3,2012) => 4 | |
(3,2013) => 2 | |
(3,2014) => 7 | |
(3,2015) => 6 | |
(3,2016) => 2 | |
(3,3000) => 8 | |
(3,4000) => 1 | |
(3,7373) => 1 | |
(3,10000) => 1 | |
(4,0) => 4037 | |
(4,1) => 415 | |
(4,2) => 91 | |
(4,3) => 47 | |
(4,4) => 19 | |
(4,5) => 7 | |
(4,6) => 1 | |
(4,8) => 1 | |
(4,9) => 3 | |
(4,10) => 1 | |
(4,2009) => 1 | |
(4,2010) => 3 | |
(4,2011) => 4 | |
(4,2012) => 1 | |
(4,2014) => 1 | |
(4,2015) => 1 | |
(4,2999) => 1 | |
(4,3000) => 3 | |
(4,3001) => 2 | |
(5,0) => 6 | |
(5,1) => 1 | |
(5,2) => 1 | |
(5,3) => 1 | |
(6,0) => 2 | |
(8,3) => 2 | |
Number of releases => number of packages | |
1 => 2168 | |
2 => 1716 | |
3 => 1359 | |
4 => 945 | |
5 => 688 | |
6 => 532 | |
7 => 448 | |
8 => 341 | |
9 => 295 | |
10 => 238 | |
11 => 202 | |
12 => 199 | |
13 => 145 | |
14 => 111 | |
15 => 118 | |
16 => 99 | |
17 => 94 | |
18 => 79 | |
19 => 87 | |
20 => 64 | |
21 => 62 | |
22 => 53 | |
23 => 39 | |
24 => 42 | |
25 => 32 | |
26 => 33 | |
27 => 31 | |
28 => 21 | |
29 => 18 | |
30 => 21 | |
31 => 24 | |
32 => 20 | |
33 => 22 | |
34 => 13 | |
35 => 13 | |
36 => 11 | |
37 => 14 | |
38 => 14 | |
39 => 13 | |
40 => 10 | |
41 => 10 | |
42 => 5 | |
43 => 6 | |
44 => 6 | |
45 => 8 | |
46 => 40 | |
47 => 8 | |
48 => 5 | |
49 => 4 | |
50 => 9 | |
51 => 8 | |
52 => 7 | |
53 => 7 | |
54 => 7 | |
55 => 3 | |
56 => 1 | |
57 => 3 | |
58 => 2 | |
60 => 4 | |
61 => 4 | |
62 => 2 | |
63 => 3 | |
65 => 2 | |
66 => 4 | |
67 => 4 | |
68 => 1 | |
70 => 2 | |
71 => 2 | |
72 => 2 | |
73 => 1 | |
75 => 1 | |
76 => 1 | |
77 => 3 | |
78 => 1 | |
79 => 1 | |
80 => 2 | |
81 => 3 | |
82 => 2 | |
85 => 2 | |
86 => 1 | |
88 => 2 | |
93 => 1 | |
94 => 1 | |
100 => 3 | |
107 => 1 | |
110 => 1 | |
118 => 1 | |
119 => 2 | |
123 => 2 | |
131 => 1 | |
132 => 1 | |
135 => 1 | |
150 => 1 | |
153 => 1 | |
155 => 1 | |
158 => 1 | |
160 => 1 | |
169 => 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment