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
|
#!/usr/bin/python3
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
#
import fileinput
import sys
import time
from datetime import datetime
import re
import json
import operator
releases = {
'etch': 'Debian GNU/Linux 4.0 (etch)',
'lenny': 'Debian GNU/Linux 5.0 (lenny)',
'squeeze': 'Debian GNU/Linux 6.0 (squeeze)',
'wheezy': 'Debian GNU/Linux 7.0 (wheezy)',
'jessie': 'Debian GNU/Linux 8.0 (jessie)',
'stretch': 'Debian GNU/Linux 9.0 (stretch)',
'buster': 'Debian GNU/Linux 10.0 (buster)',
'bullseye': 'Debian GNU/Linux 11.0 (bullseye)',
'bookworm': 'Debian GNU/Linux 12.0 (bookworm)',
'trixie': 'Debian testing (trixie)',
'forky': 'Debian future (forky)',
'sid': 'Debian unstable (sid)',
'hardy': 'Ubuntu 08.04 LTS "Hardy Heron" (hardy)',
'jaunty': 'Ubuntu 09.04 "Jaunty Jackalope" (jaunty)',
'karmic': 'Ubuntu 09.10 "Karmic Koala" (karmic)',
'lucid': 'Ubuntu 10.04 LTS "Lucid Lynx" (lucid)',
'maverick': 'Ubuntu 10.10 "Maverick Meerkat" (maverick)',
'natty': 'Ubuntu 11.04 "Natty Narwhal" (natty)',
'oneiric': 'Ubuntu 11.10 "Oneiric Ocelot" (oneiric)',
'precise': 'Ubuntu 12.04 LTS "Precise Pangolin" (precise)',
'quantal': 'Ubuntu 12.10 "Quantal Quetzal" (quantal)',
'raring': 'Ubuntu 13.04 "Raring Ringtail" (raring)',
'saucy': 'Ubuntu 13.10 "Saucy Salamander" (saucy)',
'trusty': 'Ubuntu 14.04 "Trusty Tahr" (trusty)',
'utopic': 'Ubuntu 14.10 "Utopic Unicorn" (utopic)',
'vivid': 'Ubuntu 15.04 "Vivid Vervet" (vivid)',
'wily': 'Ubuntu 15.10 "Wily Werewolf" (wily)',
'xenial': 'Ubuntu 16.04 "Xenial Xerus" (xenial)',
'yakkety': 'Ubuntu 16.10 "Yakkety Yak" (yakkety)',
'zesty': 'Ubuntu 17.04 "Zesty Zapus" (zesty)',
'artful': 'Ubuntu 17.10 "Artful Aardvark" (artful)',
'bionic': 'Ubuntu 18.04 "Bionic Beaver (bionic)',
'cosmic': 'Ubuntu 18.10 "Cosmic Cuttlefish" (cosmic)',
'disco': 'Ubuntu 19.04 "Disco Dingo" (disco)',
'eoan': 'Ubuntu 19.10 "Eoan Ermin" (eoan)',
'focal': 'Ubuntu 20.04 "Focal Fossa" (focal)',
'groovy': 'Ubuntu 20.10 "Groovy Gorilla" (groovy)',
'hirsute': 'Ubuntu 21.04 "Hirsute Hippo" (hirsute)',
'impish': 'Ubuntu 21.10 "Impish Indri" (impish)',
'jammy': 'Ubuntu 22.04 "Jammy Jellyfish" (jammy)',
'noble': 'Ubuntu 24.04 "Noble Numbat" (noble)',
}
if __name__ == '__main__':
data = {}
# get the IP, date and target release
# the date is truncated to a month/year combo
listget = re.compile(r'^([0-9.:]*) .*\[([^:]*).*GET /lists/([a-z]*)')
for line in fileinput.FileInput(openhook=fileinput.hook_compressed):
if isinstance(line, bytes):
line = line.decode()
match = listget.match(line)
if not match:
continue
addr, date, release = match.groups()
if not release in releases:
# ignore fantasy names
continue
date = datetime.strptime(date, '%d/%b/%Y')
# truncate to a week
try:
date = datetime(date.year, date.month, (date.day//7) * 7 + 1)
except ValueError:
# only on Feb28...
date = datetime(date.year, date.month, (date.day//7) * 7)
# microseconds since epoch
date = int(time.mktime(date.timetuple()) * 1000)
rstats = data.setdefault(releases[release], {})
rtime = rstats.setdefault(date, 0)
rtime += 1
rstats[date] = rtime
data[releases[release]] = rstats
# determine the union of all timestamps
timestamps = set()
for codename, stats in data.items():
timestamps.update(list(stats.keys()))
export = [{'key': release,
'values': [[ts, float(data[release].setdefault(ts, 0)) / 7]
for ts in sorted(timestamps)]}
for release in sorted(data)]
print(json.dumps(export))
|