Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

22 changed files with 499 additions and 737 deletions

847
data.json
View File

@ -1,425 +1,424 @@
{ {
"AlmaLinux": { "AlmaLinux": {
"out_of_sync_since": null, "out_of_sync_since": null,
"out_of_sync_interval": 86400, "out_of_sync_interval": 86400,
"csc": "", "csc": "",
"upstream": "https://repo.almalinux.org/", "upstream": "https://repo.almalinux.org/",
"file": "almalinux/TIME" "file": "almalinux/TIME"
}, },
"Alpine": { "Alpine": {
"out_of_sync_since": null, "out_of_sync_since": null,
"out_of_sync_interval": 86400, "out_of_sync_interval": 86400,
"csc": "", "csc": "",
"upstream": "https://uk.alpinelinux.org/", "upstream": "https://uk.alpinelinux.org/",
"file": "alpine/last-updated" "file": "alpine/last-updated"
}, },
"Apache": { "Apache": {
"out_of_sync_since": null, "out_of_sync_since": null,
"out_of_sync_interval": 86400, "out_of_sync_interval": 86400,
"csc": "apache/", "csc": "apache/",
"upstream": "https://downloads.apache.org/", "upstream": "https://downloads.apache.org/",
"file": "zzz/time.txt" "file": "zzz/time.txt"
}, },
"Arch": { "Arch": {
"out_of_sync_since": null, "out_of_sync_since": null,
"out_of_sync_interval": 86400, "out_of_sync_interval": 86400,
"csc": "archlinux/", "csc": "archlinux/",
"upstream": "http://arch.mirror.constant.com/", "upstream": "http://arch.mirror.constant.com/",
"file": "lastupdate" "file": "lastupdate"
}, },
"Artix": { "Artix": {
"out_of_sync_since": null, "out_of_sync_since": null,
"out_of_sync_interval": 86400, "out_of_sync_interval": 86400,
"csc": "artixlinux/", "csc": "artixlinux/",
"upstream": "https://mirror1.artixlinux.org/repos/" "upstream": "https://mirror1.artixlinux.org/repos/"
}, },
"CentOS": { "CentOS": {
"out_of_sync_since": null, "out_of_sync_since": null,
"out_of_sync_interval": 86400, "out_of_sync_interval": 86400,
"csc": "", "csc": "",
"upstream": "https://mirrors.edge.kernel.org/", "upstream": "https://mirrors.edge.kernel.org/",
"file": "centos/TIME" "file": "centos/TIME"
}, },
"Ceph": { "Ceph": {
"out_of_sync_since": null, "out_of_sync_since": null,
"out_of_sync_interval": 86400, "out_of_sync_interval": 86400,
"csc": "ceph/", "csc": "ceph/",
"upstream": "https://download.ceph.com/", "upstream": "https://download.ceph.com/",
"file": "timestamp" "file": "timestamp"
}, },
"CPAN": { "CPAN": {
"out_of_sync_interval": 172800, "out_of_sync_interval": 172800
"out_of_sync_since": null },
}, "cran": {
"cran": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://cran.r-project.org/mirmon_report.html",
"upstream": "https://cran.r-project.org/mirmon_report.html", "file": ""
"file": "" },
}, "ctan": {
"ctan": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://www.ctan.org/mirrors/mirmon",
"upstream": "https://www.ctan.org/mirrors/mirmon", "file": ""
"file": "" },
}, "Cygwin": {
"Cygwin": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "cygwin/",
"csc": "cygwin/", "upstream": "https://cygwin.com/pub/cygwin/",
"upstream": "https://cygwin.com/pub/cygwin/", "file": "x86/sha512.sum"
"file": "x86/sha512.sum" },
}, "Debian": {
"Debian": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://ftp-master.debian.org/",
"upstream": "https://ftp-master.debian.org/", "file": "debian/project/trace/master"
"file": "debian/project/trace/master" },
}, "DebianCD": {
"DebianCD": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "http://debian.mirror.estruxture.net/",
"upstream": "http://debian.mirror.estruxture.net/", "file": "debian-cd/project/trace/cdimage.debian.org"
"file": "debian-cd/project/trace/cdimage.debian.org" },
}, "DebianMultimedia": {
"DebianMultimedia": { "out_of_sync_since": null,
"out_of_sync_since": 1659116719, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "debian-multimedia/",
"csc": "debian-multimedia/", "upstream": "http://debian-mirrors.sdinet.de/deb-multimedia/",
"upstream": "http://debian-mirrors.sdinet.de/deb-multimedia/", "file": "project/trace/deb-multimedia.org"
"file": "project/trace/deb-multimedia.org" },
}, "DebianPorts": {
"DebianPorts": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://deb.debian.org/",
"upstream": "https://deb.debian.org/", "file": "debian-ports/project/trace/porta.debian.org",
"file": "debian-ports/project/trace/porta.debian.org", "exclude": true
"exclude": true },
}, "DebianSecurity": {
"DebianSecurity": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://deb.debian.org/",
"upstream": "https://deb.debian.org/", "file": "debian-security/project/trace/master"
"file": "debian-security/project/trace/master" },
}, "Eclipse": {
"Eclipse": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 172800,
"out_of_sync_interval": 172800, "csc": "eclipse/",
"csc": "eclipse/", "upstream": "http://download.eclipse.org/",
"upstream": "http://download.eclipse.org/", "file": "TIME"
"file": "TIME" },
}, "Fedora": {
"Fedora": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 259200, "csc": "fedora/",
"csc": "fedora/", "upstream": "http://fedora.mirror.iweb.com/",
"upstream": "http://fedora.mirror.iweb.com/", "file": "linux/development/rawhide/COMPOSE_ID"
"file": "linux/development/rawhide/COMPOSE_ID" },
}, "FreeBSD": {
"FreeBSD": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "http://ftp4.freebsd.org/pub/",
"upstream": "http://ftp4.freebsd.org/pub/", "file": "FreeBSD/TIMESTAMP"
"file": "FreeBSD/TIMESTAMP" },
}, "GentooDistfiles": {
"GentooDistfiles": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "gentoo-distfiles/",
"csc": "gentoo-distfiles/", "upstream": "http://gentoo.mirrors.tera-byte.com/",
"upstream": "http://gentoo.mirrors.tera-byte.com/", "file": "distfiles/timestamp.dev-local"
"file": "distfiles/timestamp.dev-local" },
}, "GentooPortage": {
"GentooPortage": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "rsync://rsync4.ca.gentoo.org/",
"csc": "rsync://rsync4.ca.gentoo.org/", "upstream": "https://mirrorstats.gentoo.org/rsync/",
"upstream": "https://mirrorstats.gentoo.org/rsync/", "upstream1": "rsync://rsync1.de.gentoo.org/",
"upstream1": "rsync://rsync1.de.gentoo.org/", "upstream2": "rsync://rsync8.de.gentoo.org/",
"upstream2": "rsync://rsync8.de.gentoo.org/", "file": "gentoo-portage/Manifest"
"file": "gentoo-portage/Manifest" },
}, "GNOME": {
"GNOME": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "gnome/",
"csc": "gnome/", "upstream1": "https://download.gnome.org/",
"upstream1": "https://download.gnome.org/", "upstream2": "https://mirrors.dotsrc.org/gnome/",
"upstream2": "https://mirrors.dotsrc.org/gnome/", "upstream3": "https://muug.ca/mirror/gnome/",
"upstream3": "https://muug.ca/mirror/gnome/", "file1": "core/",
"file1": "core/", "file2": "cache.json"
"file2": "cache.json" },
}, "GNU": {
"GNU": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://mirrors.kernel.org/",
"upstream": "https://mirrors.kernel.org/", "file": "gnu/mirror-updated-timestamp.txt"
"file": "gnu/mirror-updated-timestamp.txt" },
}, "Gutenberg": {
"Gutenberg": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 172800,
"out_of_sync_interval": 172800, "csc": "gutenberg/",
"csc": "gutenberg/", "upstream": "https://gutenberg.pglaf.org/",
"upstream": "https://gutenberg.pglaf.org/", "file": "gutenberg.dcs"
"file": "gutenberg.dcs" },
}, "IPFire": {
"IPFire": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 172800
"out_of_sync_interval": 172800 },
}, "KDE": {
"KDE": { "out_of_sync_since": null,
"out_of_sync_since": 1659116720, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "kde/",
"csc": "kde/", "upstream": "https://kde.c3sl.ufpr.br/",
"upstream": "https://kde.c3sl.ufpr.br/", "file": "ls-lR"
"file": "ls-lR" },
}, "KDEApplicationData": {
"KDEApplicationData": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "kde-applicationdata/",
"csc": "kde-applicationdata/", "upstream": "https://cdn.files.kde.org/",
"upstream": "https://cdn.files.kde.org/", "file": "last-updated"
"file": "last-updated" },
}, "Kernel": {
"Kernel": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "kernel.org/",
"csc": "kernel.org/", "upstream": "https://mirrors.edge.kernel.org/pub/",
"upstream": "https://mirrors.edge.kernel.org/pub/", "file": "linux/kernel/next/sha256sums.asc"
"file": "linux/kernel/next/sha256sums.asc" },
}, "linuxmint": {
"linuxmint": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "linuxmint/",
"csc": "linuxmint/", "upstream": "https://mirrors.edge.kernel.org/linuxmint/",
"upstream": "https://mirrors.edge.kernel.org/linuxmint/", "file": ""
"file": "" },
}, "linuxmint_packages": {
"linuxmint_packages": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "linuxmint-packages/",
"csc": "linuxmint-packages/", "upstream": "https://mirrors.edge.kernel.org/linuxmint-packages/",
"upstream": "https://mirrors.edge.kernel.org/linuxmint-packages/", "file": "dists/"
"file": "dists/" },
}, "macports": {
"macports": { "out_of_sync_since": null,
"out_of_sync_since": 1642827723, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "MacPorts/mpdistfiles/",
"csc": "MacPorts/mpdistfiles/", "upstream": "https://distfiles.macports.org/",
"upstream": "https://distfiles.macports.org/", "file": "ports.tar.gz"
"file": "ports.tar.gz" },
}, "manjaro": {
"manjaro": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://repo.manjaro.org/",
"upstream": "https://repo.manjaro.org/", "file": ""
"file": "" },
}, "mxlinux": {
"mxlinux": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "http://rsync-mxlinux.org/mirmon/packages.html",
"upstream": "http://rsync-mxlinux.org/mirmon/packages.html", "file": ""
"file": "" },
}, "mxlinux_iso": {
"mxlinux_iso": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "mxlinux-iso/",
"csc": "mxlinux-iso/", "upstream": "http://rsync-mxlinux.org/mirmon/index.html",
"upstream": "http://rsync-mxlinux.org/mirmon/index.html", "mirrors": [
"mirrors": [ "http://mirror.its.dal.ca/mxlinux-cd/",
"http://mirror.its.dal.ca/mxlinux-cd/", "http://mirror.umd.edu/mxlinux-iso/"
"http://mirror.umd.edu/mxlinux-iso/" ],
], "file": ""
"file": "" },
}, "mySQL": {
"mySQL": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "mysql/",
"csc": "mysql/", "upstream": "http://mirrors.sunsite.dk/mysql/",
"upstream": "http://mirrors.sunsite.dk/mysql/", "file": "last-updated.txt"
"file": "last-updated.txt" },
}, "netbsd": {
"netbsd": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "NetBSD/",
"csc": "NetBSD/", "upstream": "http://ftp.netbsd.org/pub/NetBSD/",
"upstream": "http://ftp.netbsd.org/pub/NetBSD/", "file": ""
"file": "" },
}, "nongnu": {
"nongnu": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "nongnu/",
"csc": "nongnu/", "upstream": "http://download-mirror.savannah.gnu.org/releases/",
"upstream": "http://download-mirror.savannah.gnu.org/releases/", "file": "00_TIME.txt"
"file": "00_TIME.txt" },
}, "OpenBSD": {
"OpenBSD": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://ftp.openbsd.org/pub/",
"upstream": "https://ftp.openbsd.org/pub/", "file": "OpenBSD/timestamp",
"file": "OpenBSD/timestamp", "exclude": true
"exclude": true },
}, "opensuse": {
"opensuse": { "out_of_sync_since": null,
"out_of_sync_since": 1648699331, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "opensuse/update/",
"csc": "opensuse/update/", "upstream": "http://opensuse-mirror-gce-us.opensu.se/update/",
"upstream": "http://opensuse-mirror-gce-us.opensu.se/update/", "file": ""
"file": "" },
}, "parabola": {
"parabola": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "parabola/",
"csc": "parabola/", "upstream": "https://repo.parabola.nu/",
"upstream": "https://repo.parabola.nu/", "file": "lastsync"
"file": "lastsync" },
}, "pkgsrc": {
"pkgsrc": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "pkgsrc/",
"csc": "pkgsrc/", "upstream": "http://ftp.netbsd.org/pub/pkgsrc/",
"upstream": "http://ftp.netbsd.org/pub/pkgsrc/", "file": "MIRROR-TIMESTAMP",
"file": "MIRROR-TIMESTAMP", "exclude": true
"exclude": true },
}, "puppy_linux": {
"puppy_linux": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "puppylinux/",
"csc": "puppylinux/", "upstream": "https://distro.ibiblio.org/puppylinux/",
"upstream": "https://distro.ibiblio.org/puppylinux/", "file": ""
"file": "" },
}, "qtproject": {
"qtproject": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "qtproject/",
"csc": "qtproject/", "upstream": "https://download.qt.io/",
"upstream": "https://download.qt.io/", "file": "timestamp.txt",
"file": "timestamp.txt", "exclude": true
"exclude": true },
}, "racket": {
"racket": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "racket/racket-installers/",
"csc": "racket/racket-installers/", "upstream": "https://mirror.racket-lang.org/installers/",
"upstream": "https://mirror.racket-lang.org/installers/", "file": ""
"file": "" },
}, "raspberrypi": {
"raspberrypi": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "raspberrypi/debian/",
"csc": "raspberrypi/debian/", "upstream": "https://archive.raspberrypi.org/debian/",
"upstream": "https://archive.raspberrypi.org/debian/", "file": "dists/"
"file": "dists/" },
}, "raspbian": {
"raspbian": { "out_of_sync_since": null,
"out_of_sync_since": 1659116721, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "raspbian/",
"csc": "raspbian/", "upstream": "http://archive.raspbian.org/",
"upstream": "http://archive.raspbian.org/", "file": "snapshotindex.txt"
"file": "snapshotindex.txt" },
}, "sage": {
"sage": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "",
"upstream": "", "file": "sage/src/index.html"
"file": "sage/src/index.html" },
}, "saltstack": {
"saltstack": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "saltstack/",
"csc": "saltstack/", "upstream": "https://repo.saltproject.io/",
"upstream": "https://repo.saltproject.io/", "file": ""
"file": "" },
}, "slackware": {
"slackware": { "out_of_sync_since": null,
"out_of_sync_since": 1642827723, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "slackware/",
"csc": "slackware/", "upstream": "https://mirrors.slackware.com/slackware/",
"upstream": "https://mirrors.slackware.com/slackware/", "file": ""
"file": "" },
}, "tdf": {
"tdf": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "tdf/",
"csc": "tdf/", "upstream": "https://download.documentfoundation.org/",
"upstream": "https://download.documentfoundation.org/", "file": "TIMESTAMP"
"file": "TIMESTAMP" },
}, "trisquel": {
"trisquel": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "trisquel/",
"csc": "trisquel/", "upstream": "http://rsync.trisquel.info/trisquel/dists/",
"upstream": "http://rsync.trisquel.info/trisquel/dists/", "mirrors": [
"mirrors": [ "https://mirror.fsf.org/trisquel-images/",
"https://mirror.fsf.org/trisquel-images/", "http://mirrors.ocf.berkeley.edu/trisquel-images/"
"http://mirrors.ocf.berkeley.edu/trisquel-images/" ],
], "file": ""
"file": "" },
}, "ubuntu": {
"ubuntu": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "",
"csc": "", "upstream": "https://launchpad.net/ubuntu/+mirror/mirror.csclub.uwaterloo.ca-archive",
"upstream": "https://launchpad.net/ubuntu/+mirror/mirror.csclub.uwaterloo.ca-archive", "file": ""
"file": "" },
}, "ubuntu_ports": {
"ubuntu_ports": { "out_of_sync_since": null,
"out_of_sync_since": 1651550528, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "ubuntu-ports/",
"csc": "ubuntu-ports/", "upstream": "http://ports.ubuntu.com/ubuntu-ports/",
"upstream": "http://ports.ubuntu.com/ubuntu-ports/", "file": "dists/"
"file": "dists/" },
}, "ubuntu_ports_releases": {
"ubuntu_ports_releases": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "ubuntu-ports-releases/",
"csc": "ubuntu-ports-releases/", "upstream": "https://cdimage.ubuntu.com/releases/",
"upstream": "https://cdimage.ubuntu.com/releases/", "file": ""
"file": "" },
}, "ubuntu_releases": {
"ubuntu_releases": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 172800,
"out_of_sync_interval": 172800, "csc": "",
"csc": "", "upstream": "https://launchpad.net/ubuntu/+mirror/mirror.csclub.uwaterloo.ca-release",
"upstream": "https://launchpad.net/ubuntu/+mirror/mirror.csclub.uwaterloo.ca-archive", "file": ""
"file": "" },
}, "vlc": {
"vlc": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "vlc/",
"csc": "vlc/", "upstream": "http://download.videolan.org/pub/videolan/",
"upstream": "http://download.videolan.org/pub/videolan/", "file": "trace"
"file": "trace" },
}, "x_org": {
"x_org": { "out_of_sync_since": null,
"out_of_sync_since": 1657512131, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "x.org/individual/",
"csc": "x.org/individual/", "upstream": "https://www.x.org/releases/individual/",
"upstream": "https://www.x.org/releases/individual/", "file": ""
"file": "" },
}, "xiph": {
"xiph": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "xiph/releases/",
"csc": "xiph/releases/", "upstream": "https://ftp.osuosl.org/pub/xiph/releases/",
"upstream": "https://ftp.osuosl.org/pub/xiph/releases/", "file": ""
"file": "" },
}, "xubuntu_releases": {
"xubuntu_releases": { "out_of_sync_since": null,
"out_of_sync_since": null, "out_of_sync_interval": 86400,
"out_of_sync_interval": 86400, "csc": "xubuntu-releases/",
"csc": "xubuntu-releases/", "upstream": "https://cdimage.ubuntu.com/xubuntu/releases/",
"upstream": "https://cdimage.ubuntu.com/xubuntu/releases/", "file": ""
"file": "" }
} }
}

99
main.py
View File

@ -7,88 +7,59 @@ This mirror status checker determines whether CSC mirror is up-to-date with upst
import time import time
import sys import sys
import requests import requests
from multiprocessing import Pool, Manager
from typing import Optional
from time import sleep, localtime, strftime
from projects import * from projects import *
import json import json
NUM_THREAD = 16
MAX_RETRY = 3
RETRY_TIMEOUT = 30 # In seconds
def safe_print(*args, **kwargs): def safe_print(*args, **kwargs):
# When run with 'chronic' and 'timeout', stdout gets suppressed # When run with 'chronic' and 'timeout', stdout gets suppressed
# due to buffering. Make sure to always flush the output. # due to buffering. Make sure to always flush the output.
print(*args, **kwargs, flush=True) print(*args, **kwargs, flush=True)
# Return None if no error occurs and a string for error message otherwise
def check_project(args) -> Optional[str]:
current_time = int(time.time())
project, data = args
try:
project_class = getattr(sys.modules[__name__], project)
# Skip projects we no longer mirror if __name__ == "__main__":
if data[project].get('exclude', False):
return None
checker_result = project_class.check(data, project, current_time) exit_code = 0
if checker_result:
data[project]["out_of_sync_since"] = None
return None
elif (data[project]["out_of_sync_since"] is not None
and current_time - data[project]["out_of_sync_since"] > data[project]["out_of_sync_interval"]):
now_str = strftime("%d %b %Y %H:%M:%S (local time)", localtime())
duration = current_time - data[project]["out_of_sync_since"]
return f"{project} out-of-sync at {now_str} for {duration}s"
else:
data[project]["out_of_sync_since"] = current_time
return None
except requests.exceptions.RequestException as err:
return f"{project}\n{err}"
def check_project_with_retry(args) -> bool:
project, _ = args
errs = []
for _ in range(MAX_RETRY):
res = check_project(args)
if res == None:
safe_print(f"Success: {project} up-to-date")
return True
else:
errs.append(res)
# Do nothing, try again later
sleep(RETRY_TIMEOUT)
# Max try reached, print errors
safe_print(f"Error: {project}")
for reason in errs:
safe_print(f" {reason}")
return False
def main():
data_file = 'data.json' data_file = 'data.json'
if len(sys.argv) > 1: if len(sys.argv) > 1:
data_file = sys.argv[1] data_file = sys.argv[1]
manager = Manager()
data = json.load(open(data_file)) data = json.load(open(data_file))
sync_data = manager.dict({k: manager.dict(v) for k, v in data.items()})
with Pool(NUM_THREAD) as pool: current_time = int(time.time())
all_pass = all(pool.imap(check_project_with_retry, ((k, sync_data) for k in data.keys()))) for project in data:
try:
project_class = getattr(sys.modules[__name__], project)
# Skip projects we no longer mirror
if data[project].get('exclude', False):
continue
checker_result = project_class.check(data, project, current_time)
if project in ["CPAN", "ubuntu_releases", "manjaro", "mxlinux", "cran", "ctan", "gentooportage", "Artix"]:
if checker_result:
safe_print(f"Success: {project} up-to-date")
else:
safe_print(f"Failure: {project} out-of-sync")
# Exit with non-zero status if any of the projects are not up-to-date
exit_code = 1
continue
if checker_result:
data[project]["out_of_sync_since"] = None
elif data[project]["out_of_sync_since"] is None:
data[project]["out_of_sync_since"] = current_time
elif current_time - data[project]["out_of_sync_since"] \
> data[project]["out_of_sync_interval"]:
safe_print(f"Failure: {project} out-of-sync")
# Exit with non-zero status if any of the projects are not up-to-date
exit_code = 1
continue
safe_print(f"Success: {project} up-to-date")
except requests.exceptions.RequestException as err:
safe_print(f"Error: {project}\n{err}")
with open(data_file, "w", encoding="utf-8") as file: with open(data_file, "w", encoding="utf-8") as file:
json.dump({k: dict(v) for k, v in sync_data.items()}, file, indent=' ') json.dump(data, file, indent='\t')
sys.exit(0 if all_pass else 1) sys.exit(exit_code)
if __name__ == "__main__":
main()

View File

@ -3,35 +3,7 @@ Contains Apache class
""" """
from project import Project from project import Project
from shared import CSC_MIRROR
import requests
class Apache(Project): class Apache(Project):
"""Apache class""" """Apache class"""
# Apache's time file has two segments, so we need a special function
# Example: 1648323001 rsync-he-fi
def check(data, project, current_time):
"""Check if project packages are up-to-date"""
csc_url = CSC_MIRROR + data[project]["csc"] + data[project]["file"]
upstream_url = data[project]["upstream"] + data[project]["file"]
req = requests.get(csc_url)
req.raise_for_status()
CSC = req.text
req = requests.get(upstream_url)
req.raise_for_status()
upstream = req.text
if upstream == CSC:
return True
try:
return get_timestamp_from_apache(upstream) - get_timestamp_from_apache(CSC) < data[project]["out_of_sync_interval"]
except ValueError:
print("failed to parse apache")
return False
def get_timestamp_from_apache(s: str) -> int:
real_time = s.split(" ")[0]
return int(real_time)

View File

@ -39,6 +39,6 @@ class Artix(Project):
if outdated_since is not None: if outdated_since is not None:
data[project]['out_of_sync_since'] = int(outdated_since.timestamp()) data[project]['out_of_sync_since'] = int(outdated_since.timestamp())
return current_time - data[project]['out_of_sync_since'] < data[project]['out_of_sync_interval'] return (datetime.now() - outdated_since).total_seconds() < data[project]['out_of_sync_interval']
return True return True

View File

@ -9,14 +9,12 @@ from shared import CSC_MIRROR
class CPAN(Project): class CPAN(Project):
"""CPAN class""" """CPAN class"""
@staticmethod @staticmethod
def check(data, project, current_time): def check(data, project, current_time):
res_json = requests.get("http://mirrors.cpan.org/cpan-json.txt").json() res_json = requests.get("http://mirrors.cpan.org/cpan-json.txt").json()
for mirror in res_json: for mirror in res_json:
if mirror["url"] == f"{CSC_MIRROR}CPAN/" and mirror["last_status"] == "ok": if mirror["url"] == f"{CSC_MIRROR}CPAN/":
# This is an improvised method: report we're good if CPAN think we are good return current_time - int(mirror["age"]) <= data[project]["out_of_sync_interval"]
# Change this to a more precise method if you find a better way to do it return False
return True
return False

View File

@ -8,6 +8,7 @@ from shared import CSC_MIRROR
import requests import requests
import datefinder # another date finding library import datefinder # another date finding library
from datetime import timedelta from datetime import timedelta
from datetime import datetime
import re import re
import pandas as pd import pandas as pd
@ -18,9 +19,8 @@ class cran(Project):
page = requests.get(data[project]["upstream"]).text page = requests.get(data[project]["upstream"]).text
indexOfFile = page.find("mirror.csclub.uwaterloo.ca") indexOfFile = page.find("mirror.csclub.uwaterloo.ca")
m = re.search(r'(\d+ minutes?)|(\d+ hours?)|(\d+(\.)?\d+ days?)', page[indexOfFile:]) m = re.search(r'(\d+ hour)|(\d+ hours)|(\d+(\.)?\d+ days)', page[indexOfFile:]) # solution from: https://stackoverflow.com/questions/21074100/how-to-convert-standard-timedelta-string-to-timedelta-object/21074460
duration = pd.to_timedelta(m.group(0)) duration = pd.to_timedelta(m.group(0))
data[project]["out_of_sync_since"] = current_time - duration.total_seconds()
return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s') return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s')

View File

@ -7,7 +7,8 @@ from project import Project
from shared import CSC_MIRROR from shared import CSC_MIRROR
import requests import requests
import datefinder # another date finding library import datefinder # another date finding library
from datetime import datetime, timedelta from datetime import timedelta
from datetime import datetime
import re import re
import pandas as pd import pandas as pd
@ -18,10 +19,8 @@ class ctan(Project):
page = requests.get(data[project]["upstream"]).text page = requests.get(data[project]["upstream"]).text
indexOfFile = page.find("mirror.csclub.uwaterloo.ca") indexOfFile = page.find("mirror.csclub.uwaterloo.ca")
m = re.search(r'(\d+ minutes?)|(\d+ hours?)|(\d+(\.)?\d+ days?)', page[indexOfFile:]) m = re.search(r'(\d+ hour)|(\d+ hours)|(\d+(\.)?\d+ days)', page[indexOfFile:]) # solution from: https://stackoverflow.com/questions/21074100/how-to-convert-standard-timedelta-string-to-timedelta-object/21074460
duration = pd.to_timedelta(m.group(0)) duration = pd.to_timedelta(m.group(0))
data[project]["out_of_sync_since"] = datetime.now() - duration
return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s') return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s')

View File

@ -3,37 +3,7 @@ Contains Debian class
""" """
from project import Project from project import Project
from shared import CSC_MIRROR
import requests
from datetime import datetime
import time
class Debian(Project): class Debian(Project):
"""Debian class""" """Debian class"""
@staticmethod
def check(data, project, current_time):
csc_url = CSC_MIRROR + data[project]["csc"] + data[project]["file"]
upstream_url = data[project]["upstream"] + data[project]["file"]
req = requests.get(csc_url)
req.raise_for_status()
CSC = req.text
req = requests.get(upstream_url)
req.raise_for_status()
upstream = req.text
if upstream == CSC:
return True
CSC_date = datetime.strptime(CSC.partition('\n')[0], "%a %b %d %H:%M:%S UTC %Y")
CSC_utc_time = time.mktime(CSC_date.timetuple())
upstream_date = datetime.strptime(upstream.partition('\n')[0], "%a %b %d %H:%M:%S UTC %Y")
upstream_utc_time = time.mktime(upstream_date.timetuple())
try:
return int(upstream_utc_time) - int(CSC_utc_time) < data[project]["out_of_sync_interval"]
except ValueError:
return False

View File

@ -3,40 +3,7 @@ Contains DebianCD class
""" """
from project import Project from project import Project
from shared import CSC_MIRROR
import requests
from datetime import datetime
import time
class DebianCD(Project): class DebianCD(Project):
"""DebianCD class""" """DebianCD class"""
@staticmethod
def check(data, project, current_time):
csc_url = CSC_MIRROR + data[project]["csc"] + data[project]["file"]
upstream_url = data[project]["upstream"] + data[project]["file"]
req = requests.get(csc_url)
req.raise_for_status()
CSC = req.text
req = requests.get(upstream_url)
req.raise_for_status()
upstream = req.text
if upstream == CSC:
return True
# Date Format Example: Sun 27 Mar 00:20:12 UTC 2022
date_format = "%a %d %b %H:%M:%S UTC %Y\n"
CSC_date = datetime.strptime(CSC, date_format)
CSC_utc_time = time.mktime(CSC_date.timetuple())
upstream_date = datetime.strptime(upstream, date_format)
upstream_utc_time = time.mktime(upstream_date.timetuple())
try:
return int(upstream_utc_time) - int(CSC_utc_time) < data[project]["out_of_sync_interval"]
except ValueError:
return False

View File

@ -3,40 +3,7 @@ Contains Fedora class
""" """
from project import Project from project import Project
from shared import CSC_MIRROR
import requests
from datetime import datetime
import time
class Fedora(Project): class Fedora(Project):
"""Fedora class""" """Fedora class"""
@staticmethod
def check(data, project, current_time):
csc_url = CSC_MIRROR + data[project]["csc"] + data[project]["file"]
upstream_url = data[project]["upstream"] + data[project]["file"]
req = requests.get(csc_url)
req.raise_for_status()
CSC = req.text
req = requests.get(upstream_url)
req.raise_for_status()
upstream = req.text
if upstream == CSC:
return True
# Date example: Fedora-Rawhide-20220725.n.1
date_format = "%Y%m%d"
CSC_date = datetime.strptime(CSC[15:23], "%Y%m%d")
CSC_utc_time = time.mktime(CSC_date.timetuple())
upstream_date = datetime.strptime(upstream[15:23], "%Y%m%d")
upstream_utc_time = time.mktime(upstream_date.timetuple())
try:
return upstream_utc_time - CSC_utc_time < data[project]["out_of_sync_interval"]
except ValueError:
return False

View File

@ -3,35 +3,7 @@ Contains FreeBSD class
""" """
from project import Project from project import Project
from shared import CSC_MIRROR
import requests
class FreeBSD(Project): class FreeBSD(Project):
"""FreeBSD class""" """FreeBSD class"""
# FreeBSD's time file has two segments, so we need a special function
# Example TIMESTAMP file: 1648308600 2022-03-26T15:30:00 UTC
def check(data, project, current_time):
"""Check if project packages are up-to-date"""
csc_url = CSC_MIRROR + data[project]["csc"] + data[project]["file"]
upstream_url = data[project]["upstream"] + data[project]["file"]
req = requests.get(csc_url)
req.raise_for_status()
CSC = req.text
req = requests.get(upstream_url)
req.raise_for_status()
upstream = req.text
if upstream == CSC:
return True
try:
return get_timestamp_for_freebsd(upstream) - get_timestamp_for_freebsd(CSC) < data[project]["out_of_sync_interval"]
except ValueError:
print("failed to parse apache")
return False
def get_timestamp_for_freebsd(s: str) -> int:
real_time = s.split(" ")[0]
return int(real_time)

View File

@ -3,35 +3,7 @@ Contains GentooDistfiles class
""" """
from project import Project from project import Project
from shared import CSC_MIRROR
import requests
from datetime import datetime
import time
class GentooDistfiles(Project): class GentooDistfiles(Project):
"""GentooDistfiles class""" """GentooDistfiles class"""
@staticmethod
def check(data, project, current_time):
csc_url = CSC_MIRROR + data[project]["csc"] + data[project]["file"]
upstream_url = data[project]["upstream"] + data[project]["file"]
req = requests.get(csc_url)
req.raise_for_status()
CSC = req.text
req = requests.get(upstream_url)
req.raise_for_status()
upstream = req.text
if upstream == CSC:
return True
CSC_utc_time = CSC[0:11]
upstream_utc_time = upstream[0:11]
try:
return int(upstream_utc_time) - int(CSC_utc_time) < data[project]["out_of_sync_interval"]
except ValueError:
return False

View File

@ -9,6 +9,7 @@ from project import Project
import requests import requests
import datefinder # another date finding library import datefinder # another date finding library
from datetime import timedelta from datetime import timedelta
from datetime import datetime
import re import re
import pandas as pd import pandas as pd
@ -41,9 +42,8 @@ class GentooPortage(Project):
page = requests.get(data[project]["upstream"]).text page = requests.get(data[project]["upstream"]).text
indexOfFile = page.find("rsync4.ca.gentoo.org") indexOfFile = page.find("rsync4.ca.gentoo.org")
m = re.search(r'(\d+ minutes?)|(\d+ hours?)|(\d+(\.)?\d+ days?)', page[indexOfFile:]) m = re.search(r'(\d+ hour)|(\d+ hours)|(\d+(\.)?\d+ days)', page[indexOfFile:])
duration = pd.to_timedelta(m.group(0)) duration = pd.to_timedelta(m.group(0))
data[project]["out_of_sync_since"] = current_time - duration.total_seconds()
return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s') return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s')

View File

@ -20,8 +20,7 @@ class manjaro(Project):
m = re.search(r'(?P<hours>\d+):(?P<minutes>\d+)', page[indexOfFile:]) # solution from: https://stackoverflow.com/questions/21074100/how-to-convert-standard-timedelta-string-to-timedelta-object/21074460 m = re.search(r'(?P<hours>\d+):(?P<minutes>\d+)', page[indexOfFile:]) # solution from: https://stackoverflow.com/questions/21074100/how-to-convert-standard-timedelta-string-to-timedelta-object/21074460
duration = timedelta(**{key: float(val) for key, val in m.groupdict().items()}) duration = timedelta(**{key: float(val) for key, val in m.groupdict().items()})
data[project]["out_of_sync_since"] = current_time - duration.total_seconds()
return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s') return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s')
# https://launchpad.net/ubuntu/+mirror/mirror.csclub.uwaterloo.ca-archive # https://launchpad.net/ubuntu/+mirror/mirror.csclub.uwaterloo.ca-archive

View File

@ -8,6 +8,7 @@ from shared import CSC_MIRROR
import requests import requests
import datefinder # another date finding library import datefinder # another date finding library
from datetime import timedelta from datetime import timedelta
from datetime import datetime
import re import re
import pandas as pd import pandas as pd
@ -18,9 +19,8 @@ class mxlinux(Project):
page = requests.get(data[project]["upstream"]).text page = requests.get(data[project]["upstream"]).text
indexOfFile = page.find("mirror.csclub.uwaterloo.ca") indexOfFile = page.find("mirror.csclub.uwaterloo.ca")
m = re.search(r'(\d+ minutes?)|(\d+ hours?)|(\d+(\.)?\d+ days?)', page[indexOfFile:]) m = re.search(r'(\d+ hour)|(\d+ hours)|(\d+(\.)?\d+ days)', page[indexOfFile:]) # solution from: https://stackoverflow.com/questions/21074100/how-to-convert-standard-timedelta-string-to-timedelta-object/21074460
duration = pd.to_timedelta(m.group(0)) duration = pd.to_timedelta(m.group(0))
data[project]["out_of_sync_since"] = current_time - duration.total_seconds()
return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s') return duration <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s')

View File

@ -8,6 +8,7 @@ from shared import CSC_MIRROR
import requests import requests
import datefinder # another date finding library import datefinder # another date finding library
from datetime import timedelta from datetime import timedelta
from datetime import datetime
import re import re
import pandas as pd import pandas as pd
@ -19,7 +20,7 @@ class mxlinux_iso(Project):
page = requests.get(data[project]["upstream"]).text page = requests.get(data[project]["upstream"]).text
indexOfFile = page.find("mirror.csclub.uwaterloo.ca") indexOfFile = page.find("mirror.csclub.uwaterloo.ca")
m = re.search(r'(\d+ minutes?)|(\d+ hours?)|(\d+(\.)?\d+ days?)', page[indexOfFile:]) m = re.search(r'(\d+ hour)|(\d+ hours)|(\d+(\.)?\d+ days)', page[indexOfFile:]) # solution from: https://stackoverflow.com/questions/21074100/how-to-convert-standard-timedelta-string-to-timedelta-object/21074460
duration = pd.to_timedelta(m.group(0)) duration = pd.to_timedelta(m.group(0))

View File

@ -3,31 +3,6 @@ Contains nongnu class
""" """
from project import Project from project import Project
from shared import CSC_MIRROR
import requests
from datetime import datetime
import time
class nongnu(Project): class nongnu(Project):
"""nongnu class""" """nongnu class"""
@staticmethod
def check(data, project, current_time):
csc_url = CSC_MIRROR + data[project]["csc"] + data[project]["file"]
upstream_url = data[project]["upstream"] + data[project]["file"]
req = requests.get(csc_url)
req.raise_for_status()
CSC = req.text
req = requests.get(upstream_url)
req.raise_for_status()
upstream = req.text
if upstream == CSC:
return True
try:
return int(upstream.partition('\n')[0]) - int(CSC.partition('\n')[0]) < data[project]["out_of_sync_interval"]
except ValueError:
return False

View File

@ -23,8 +23,7 @@ class raspberrypi(Project):
for i in s.find_all("a"): # for a href directories for i in s.find_all("a"): # for a href directories
href = i.attrs['href'] href = i.attrs['href']
# The raspberry pi server doesn't use a relative path to the parent directory if href.endswith("/") and href != "../" and href != "/":
if href.endswith("/") and href != "../" and href != "/" and href != "/debian/":
site_next = site+href+"Release" site_next = site+href+"Release"
if site_next not in urls: if site_next not in urls:
@ -44,7 +43,6 @@ class raspberrypi(Project):
# calling function # calling function
cls.scrape(urls1, csc_url) cls.scrape(urls1, csc_url)
cls.scrape(urls2, upstream_url) cls.scrape(urls2, upstream_url)
if (len(urls1) != len(urls2)): if (len(urls1) != len(urls2)):
return False return False

View File

@ -34,7 +34,7 @@ class slackware(Project):
hrefs2 = [i.attrs['href'] for i in s2.find_all("a")] hrefs2 = [i.attrs['href'] for i in s2.find_all("a")]
for href in hrefs1: # for a href directories for href in hrefs1: # for a href directories
if href.endswith("/") and href != "../" and href != "/" and not href.startswith("/") and not re.match(r'slackware-([1-7]|8\.0).*', href) and href != "slackware-iso/" and href != "slackware-current/" and href != "slackware-pre-1.0-beta/" and href != "unsupported/" and not href.startswith("http"): if href.endswith("/") and href != "../" and href != "/" and not href.startswith("/") and not re.match(r'slackware-([1-7]|8\.0).*', href) and href != "slackware-iso/" and href != "slackware-current/" and href != "slackware-pre-1.0-beta/" and href != "unsupported/":
# print(href) # print(href)
if href not in hrefs2: if href not in hrefs2:
return False return False

View File

@ -5,7 +5,6 @@ Contains ubuntu class
import os import os
from project import Project from project import Project
from shared import CSC_MIRROR from shared import CSC_MIRROR
from shared import NUM_UBUNTU_RELEASES
import requests import requests
import datefinder # another date finding library import datefinder # another date finding library
from datetime import timedelta from datetime import timedelta
@ -18,4 +17,4 @@ class ubuntu(Project):
@staticmethod @staticmethod
def check(data, project, current_time): def check(data, project, current_time):
page = requests.get(data[project]["upstream"]).text page = requests.get(data[project]["upstream"]).text
return page.count("Up to date") == NUM_UBUNTU_RELEASES return page.count("Up to date") == 21

View File

@ -5,7 +5,6 @@ Contains ubuntu_releases class
import os import os
from project import Project from project import Project
from shared import CSC_MIRROR from shared import CSC_MIRROR
from shared import NUM_UBUNTU_RELEASES
import requests import requests
import datefinder # another date finding library import datefinder # another date finding library
from datetime import timedelta from datetime import timedelta
@ -18,4 +17,9 @@ class ubuntu_releases(Project):
@staticmethod @staticmethod
def check(data, project, current_time): def check(data, project, current_time):
page = requests.get(data[project]["upstream"]).text page = requests.get(data[project]["upstream"]).text
return page.count("Up to date") == NUM_UBUNTU_RELEASES indexOfFile = page.find("last verified")
matches = list(datefinder.find_dates(page[indexOfFile:]))
date = matches[0] # date is of type datetime.datetime
return(pd.to_datetime(current_time, unit='s') - date.replace(tzinfo=None) <= pd.to_timedelta(data[project]["out_of_sync_interval"], unit='s'))
# https://launchpad.net/ubuntu/+mirror/mirror.csclub.uwaterloo.ca-release

View File

@ -1,4 +1,3 @@
"""Contains shared constants""" """Contains shared constants"""
CSC_MIRROR = "http://mirror.csclub.uwaterloo.ca/" CSC_MIRROR = "http://mirror.csclub.uwaterloo.ca/"
NUM_UBUNTU_RELEASES = 18