167 lines
4.7 KiB
Python
Executable File
167 lines
4.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
from datetime import timedelta, date, datetime
|
|
from io import BytesIO
|
|
from csv import DictWriter
|
|
|
|
import ftplib
|
|
import logging
|
|
|
|
|
|
logging.basicConfig()
|
|
logger = logging.getLogger("rebuild-debian-csv")
|
|
logger.setLevel(logging.DEBUG)
|
|
|
|
|
|
class Release:
|
|
def __init__(self, fileobj):
|
|
params = {}
|
|
for line in fileobj:
|
|
line = line.decode("utf-8")
|
|
if line.startswith(" ") or ": " not in line:
|
|
continue
|
|
|
|
k, v = line.strip().split(": ", 1)
|
|
params[k] = v
|
|
|
|
self.label = params.get("Label")
|
|
self.suite = params.get("Suite")
|
|
self.version = params.get("Version")
|
|
self.codename = params.get("Codename")
|
|
self.architectures = params.get("Architectures", "").split(" ")
|
|
|
|
def __repr__(self):
|
|
name = self.label
|
|
if self.version and self.suite and self.suite != self.codename:
|
|
name += f" {self.suite}/{self.version}"
|
|
elif self.version:
|
|
name += f" {self.version}"
|
|
elif self.suite:
|
|
name += f" {self.suite}"
|
|
if self.is_lts():
|
|
name += " LTS"
|
|
if self.codename:
|
|
name += f" (\"{self.codename}\")"
|
|
|
|
return name
|
|
|
|
def __eq__(self, other):
|
|
return repr(self) == repr(other)
|
|
|
|
def __lt__(self, other):
|
|
return repr(self) < repr(other)
|
|
|
|
def __hash__(self):
|
|
return hash(repr(self))
|
|
|
|
def release_date(self):
|
|
if self.label == "Ubuntu" and self.version:
|
|
try:
|
|
return datetime.strptime(self.version, "%y.%m").date()
|
|
except ValueError as e:
|
|
logger.warning("Can't parse calver %s: %s", self.version, e)
|
|
|
|
def is_lts(self):
|
|
release_date = self.release_date()
|
|
if release_date:
|
|
return release_date.year % 2 == 0 and release_date.month == 4
|
|
else:
|
|
return False
|
|
|
|
def age(self):
|
|
release_date = self.release_date()
|
|
if release_date:
|
|
return date.today() - release_date
|
|
|
|
def is_relevant(self):
|
|
if self.label not in ("Debian", "Ubuntu", ):
|
|
return False
|
|
|
|
bl1 = ("oldoldstable", "devel", )
|
|
if self.suite in bl1:
|
|
return False
|
|
|
|
bl2 = ("-updates", "-backports", "-security", "-proposed", "-sloppy", )
|
|
if any(self.suite.endswith(suffix) for suffix in bl2):
|
|
return False
|
|
|
|
if self.label == "Ubuntu":
|
|
if self.is_lts():
|
|
return self.age() < 4 * timedelta(days=365)
|
|
else:
|
|
return self.age() < timedelta(days=365)
|
|
|
|
return True
|
|
|
|
def is_experimental(self):
|
|
if self.label == "Debian" and self.suite == "experimental":
|
|
return True
|
|
if self.label == "Ubuntu" and self.age() < timedelta(days=0):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def get_releases():
|
|
ftp = ftplib.FTP("mirror.nl.leaseweb.net")
|
|
ftp.login()
|
|
logger.debug("Connected to FTP")
|
|
|
|
for distdir in ("/debian/dists", "/ubuntu/dists", ):
|
|
ftp.cwd(distdir)
|
|
distsubdirs = ftp.nlst()
|
|
assert len(distsubdirs) > 0
|
|
logger.debug("Found %d items in %s", len(distsubdirs), distdir)
|
|
|
|
for x in distsubdirs:
|
|
data = BytesIO()
|
|
try:
|
|
ftp.retrbinary(f"RETR {x}/Release", data.write)
|
|
assert data.tell() > 0
|
|
data.seek(0)
|
|
logger.debug("Downloaded %s/%s/Release", distdir, x)
|
|
|
|
yield Release(data)
|
|
except ftplib.error_perm:
|
|
pass
|
|
|
|
|
|
def write_csv(filename, releases, archs):
|
|
with open(filename, "w", newline="") as f:
|
|
w = DictWriter(f, fieldnames=("OS", "Dist", "Arch", "Name", "Exp", ))
|
|
w.writeheader()
|
|
|
|
for r in releases:
|
|
if not r.is_relevant():
|
|
continue
|
|
|
|
for arch in archs:
|
|
if arch not in r.architectures:
|
|
continue
|
|
|
|
dist = r.codename.lower()
|
|
if dist == "rc-buggy":
|
|
dist = "experimental"
|
|
|
|
w.writerow({
|
|
"OS": r.label.lower(),
|
|
"Dist": dist,
|
|
"Arch": arch,
|
|
"Name": repr(r),
|
|
"Exp": r.is_experimental(),
|
|
})
|
|
logger.debug("Wrote %s to file %s", r, filename)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
logger.info("Downloading releases...")
|
|
releases = list(sorted(set(get_releases())))
|
|
assert len(releases) > 0
|
|
logger.info("Found %d releases", len(releases))
|
|
|
|
write_csv("debians-arm.csv", releases, ("armhf", "arm64"))
|
|
logger.info("Wrote debians-arm.csv")
|
|
|
|
write_csv("debians-x86.csv", releases, ("i386", "amd64"))
|
|
logger.info("Wrote debians-x86.csv")
|