Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian....@packages.debian.org
Usertags: pu
X-Debbugs-Cc: bdr...@debian.org

There's a new Ubuntu release, so it's time to upload a distro-info-data
update for buster. I missed 0.46, but there was nothing urgent in it.
The changes in unstable since the last update are:

distro-info-data (0.47) unstable; urgency=medium

  * Add Ubuntu 21.04, Impish Indri.

 -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 10:30:18 -0400

distro-info-data (0.46) unstable; urgency=medium

  * Add "eol-server" dates matching "eol", for LTS releases, as there hasn't
    been a distinction between the two, for a while.
    (Closes: #922090, LP: #1814976).
  * Add "eol-esm" column: EOL for Ubuntu Extended Security Maintenance support.
    (LP: #1808038)
  * Drop ancient Replaces: distro-info (<< 0.3~). No longer needed.
  * Add "eol-lts" for Debian LTS (Closes: #782685)
  * Add estimated dates for Buster EOL and Buster LTS EOL.
  * Publish the data to GitLab pages. (Closes: #973904)
  * Bump Standards-Version to 4.5.1, no changes needed.
  * Bump copyright years.
  * Correct the EOL date for Debian Jessie.
  * Add Debian 13 "Trixie", with a rough date.
  * Add "up-to-date" testing tool.
  * Add an autopkgtest, running the validation and up-to-date tests.
  * "black" Python.
  * Add "eol-elts" for Debian ELTS.
  * Tweak eol and eol-esm dates, by a couple of days, for Ubuntu 6.10, 9.10,
    10.04, 12.04, 15.04, 15.10, 19.04 to match announced EOL dates.

 -- Stefano Rivera <stefa...@debian.org>  Fri, 29 Jan 2021 13:41:20 -0700

[ Reason ]
I want to update distro-info-data, so that it knows about the current
Ubuntu development release, and future Debian releases.

[ Impact ]
Currently on a Buster system:
$ ubuntu-distro-info --devel
ubuntu-distro-info: Distribution data outdated.
Please check for an update for distro-info-data. See 
/usr/share/doc/distro-info-data/README.Debian for details.

With this change:
$ ubuntu-distro-info --devel
impish

[ Tests ]
distro-info-data is just a data package. There are automated tests for
correctness and freshness.

distro-info has automated unit and integration tests.

[ Risks ]
The intention for distro-info and distro-info-data was that the data
could always be trivially backported to stable releases, however this
time there are a few changes there that make this a non-trivial update.
They got batched together, because once you're breaking the world, you
may as well do it properly:

1. New columns. distro-info didn't support unknown columns in the CSV
   data until 1.0.
2. Date corrections. distro-info used historical dates in the test
   suite, so changes break build time tests and autopkgtests.

So, I offer you two choices:
1. We backport distro-info-data 0.47 and distro-info 1.0 to buster.
   Bringing new features, and simplified unmodified backport data
   updates in the future.
   * distro-info_1.0~deb10u1.debdiff
   * distro-info-data_0.47~deb10u1.debdiff
2. We cherry-pick the important changes in distro-info-data (excluding
   those historical date corrections that break tests, and new columns).
   Future updates for buster will have to continue to do this.
   * distro-info-data_0.41+deb10u4.debdiff

With the backport approach:
    Users will need to install 2 updates together:
    distro-info Depends: distro-info-data (>= 0.46~)
    distro-info-data Breaks: distro-info (<< 1.0~)

    Other code that interprets distro-info-data directly may be surprised
    by new columns. All reverse-dependencies in the archive have been
    checked, and won't be affected.

With the cherry-pick approach:
    Negligible risk to users, it's a new entry in the Debian & Ubuntu
    releases tables, and EOL updates for Jessie and Buster (guessed).

    Future updates will have to continue to cherry-pick, which means
    they won't be tested as well as straight backports.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in stable
  [x] the issue is verified as fixed in unstable

[ Changes ]

backport approach:

    distro-info-data (0.47~deb10u1) buster; urgency=medium

      * Backport 0.47 to buster. Highlights:
        - Add "eol-esm" for Ubuntu Extended Security Maintenance support.
        - Add "eol-lts" for Debian LTS (Closes: #782685)
        - Add "eol-elts" for Debian ELTS.
        - Add estimated dates for Buster EOL and Buster LTS EOL.
        - Add Debian 13 "Trixie", with a rough date.
        - Correct the EOL date for Debian Jessie.
        - Tweak eol and eol-esm dates, by a couple of days, for Ubuntu 6.10, 
9.10,
          10.04, 12.04, 15.04, 15.10, 19.04 to match announced EOL dates.
        - Add Ubuntu 21.04, Impish Indri.

    -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 11:46:22 -0400

    distro-info-data (0.47) unstable; urgency=medium

      * Add Ubuntu 21.04, Impish Indri.

     -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 10:30:18 -0400

    distro-info-data (0.46) unstable; urgency=medium

      * Add "eol-server" dates matching "eol", for LTS releases, as there hasn't
        been a distinction between the two, for a while.
        (Closes: #922090, LP: #1814976).
      * Add "eol-esm" column: EOL for Ubuntu Extended Security Maintenance 
support.
        (LP: #1808038)
      * Drop ancient Replaces: distro-info (<< 0.3~). No longer needed.
      * Add "eol-lts" for Debian LTS (Closes: #782685)
      * Add estimated dates for Buster EOL and Buster LTS EOL.
      * Publish the data to GitLab pages. (Closes: #973904)
      * Bump Standards-Version to 4.5.1, no changes needed.
      * Bump copyright years.
      * Correct the EOL date for Debian Jessie.
      * Add Debian 13 "Trixie", with a rough date.
      * Add "up-to-date" testing tool.
      * Add an autopkgtest, running the validation and up-to-date tests.
      * "black" Python.
      * Add "eol-elts" for Debian ELTS.
      * Tweak eol and eol-esm dates, by a couple of days, for Ubuntu 6.10, 9.10,
        10.04, 12.04, 15.04, 15.10, 19.04 to match announced EOL dates.

     -- Stefano Rivera <stefa...@debian.org>  Fri, 29 Jan 2021 13:41:20 -0700

    and

    distro-info (1.0~deb10u1) buster; urgency=medium

      * Backport distro-info 1.0 to buster. Highlights:
        - Add support for Debian LTS (Closes: #782685)
        - Add support for Debian ELTS.
        - Provide support for the milestone eol-esm and add filters for
          supported-esm to ubuntu-distro-info along with the python and perl
          modules. (LP: #1808038)
        - Handle currently unknown columns in CSV data.
      * Re-instate python2 support.
      * Revert: Rename build dependency pylint3 to pylint.
      * Revert: Switch to debhelper 13.
      * Tweak Python indentation to please an older pylint.
      * Adjust {Build-,}Depends on distro-info-data to (>= 0.46~).

     -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 11:54:50 -0400

    distro-info (1.0) unstable; urgency=medium

      [ Debian Janitor ]
      * Mark libdistro-info-perl as Multi-Arch: foreign.

      [ Stefano Rivera ]
      * Bump standards-Version to 4.5.1, no changes needed.
      * Bump copyright years.
      * Re-black Python.
      * Add support for Debian LTS (Closes: #782685)
      * Depend on distro-info-data (>= 0.46), with extra columns for
        Debian LTS and Ubuntu ESM.
      * Ignore W503 warnings from flake8, they are PEP-8 incompatible.
      * Handle currently unknown columns in CSV data.
      * Drop old Breaks+Replaces on ubuntu-dev-tools, no longer needed.
      * Reorganise help into a slightly more logical order.
      * Add support for Debian ELTS.
      * Update tests to match old date adjustments in distro-info-data 0.46.

      [ Brian Murray ]
      * Provide support for the milestone eol-esm and add filters for
        supported-esm to ubuntu-distro-info along with the python and perl
        modules. (LP: #1808038)
      * Only include LTS releases when filtering by supported-esm.

      [ Steve Langasek ]
      * Override uninteresting flake8 warnings about imports and doc strings.
      * Don't run tests over the distro_info_test directory, which is pointless
        and recursive.

     -- Stefano Rivera <stefa...@debian.org>  Fri, 29 Jan 2021 13:35:30 -0700

    distro-info (0.24) unstable; urgency=medium

      * Fix issues found by pylint 2.6.0 (Closes: #971094)
      * Blacken Python code
      * python: Define sets directly
      * Bump Standards-Version to 4.5.0
      * Switch to debhelper 13

     -- Benjamin Drung <bdr...@debian.org>  Mon, 28 Sep 2020 19:36:32 +0200

    distro-info (0.23) unstable; urgency=medium

      * Drop python2 support; Closes: #943052, #936408

     -- Sandro Tosi <mo...@debian.org>  Wed, 08 Jan 2020 23:06:26 -0500

    distro-info (0.22) unstable; urgency=medium

      * Drop testing Python 2 code with Pylint
      * Rename build dependency pylint3 to pylint (Closes: #940178)
      * Switch to debhelper 12
      * Bump Standards-Version to 4.4.0 (no changes needed)

     -- Benjamin Drung <bdr...@debian.org>  Sat, 14 Sep 2019 15:44:13 +0200

cherry-pick approach:

    distro-info-data (0.41+deb10u4) UNRELEASED; urgency=medium

      * Update data to 0.46, without new columns:
        - Add estimated date for Buster EOL.
        - Correct the EOL date for Debian Jessie.
        - Add Debian 13 "Trixie", with a rough date.
        - Add Ubuntu 21.04, Impish Indri.

     -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 11:07:13 -0400

SR
diff -Nru distro-info-0.21/debian/changelog 
distro-info-1.0~deb10u1/debian/changelog
--- distro-info-0.21/debian/changelog   2019-02-09 19:29:24.000000000 -0400
+++ distro-info-1.0~deb10u1/debian/changelog    2021-04-22 11:54:50.000000000 
-0400
@@ -1,3 +1,77 @@
+distro-info (1.0~deb10u1) buster; urgency=medium
+
+  * Backport distro-info 1.0 to buster. Highlights:
+    - Add support for Debian LTS (Closes: #782685)
+    - Add support for Debian ELTS.
+    - Provide support for the milestone eol-esm and add filters for
+      supported-esm to ubuntu-distro-info along with the python and perl
+      modules. (LP: #1808038)
+    - Handle currently unknown columns in CSV data.
+  * Re-instate python2 support.
+  * Revert: Rename build dependency pylint3 to pylint.
+  * Revert: Switch to debhelper 13.
+  * Tweak Python indentation to please an older pylint.
+  * Adjust {Build-,}Depends on distro-info-data to (>= 0.46~).
+
+ -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 11:54:50 -0400
+
+distro-info (1.0) unstable; urgency=medium
+
+  [ Debian Janitor ]
+  * Mark libdistro-info-perl as Multi-Arch: foreign.
+
+  [ Stefano Rivera ]
+  * Bump standards-Version to 4.5.1, no changes needed.
+  * Bump copyright years.
+  * Re-black Python.
+  * Add support for Debian LTS (Closes: #782685)
+  * Depend on distro-info-data (>= 0.46), with extra columns for
+    Debian LTS and Ubuntu ESM.
+  * Ignore W503 warnings from flake8, they are PEP-8 incompatible.
+  * Handle currently unknown columns in CSV data.
+  * Drop old Breaks+Replaces on ubuntu-dev-tools, no longer needed.
+  * Reorganise help into a slightly more logical order.
+  * Add support for Debian ELTS.
+  * Update tests to match old date adjustments in distro-info-data 0.46.
+
+  [ Brian Murray ]
+  * Provide support for the milestone eol-esm and add filters for
+    supported-esm to ubuntu-distro-info along with the python and perl
+    modules. (LP: #1808038)
+  * Only include LTS releases when filtering by supported-esm.
+
+  [ Steve Langasek ]
+  * Override uninteresting flake8 warnings about imports and doc strings.
+  * Don't run tests over the distro_info_test directory, which is pointless
+    and recursive.
+
+ -- Stefano Rivera <stefa...@debian.org>  Fri, 29 Jan 2021 13:35:30 -0700
+
+distro-info (0.24) unstable; urgency=medium
+
+  * Fix issues found by pylint 2.6.0 (Closes: #971094)
+  * Blacken Python code
+  * python: Define sets directly
+  * Bump Standards-Version to 4.5.0
+  * Switch to debhelper 13
+
+ -- Benjamin Drung <bdr...@debian.org>  Mon, 28 Sep 2020 19:36:32 +0200
+
+distro-info (0.23) unstable; urgency=medium
+
+  * Drop python2 support; Closes: #943052, #936408
+
+ -- Sandro Tosi <mo...@debian.org>  Wed, 08 Jan 2020 23:06:26 -0500
+
+distro-info (0.22) unstable; urgency=medium
+
+  * Drop testing Python 2 code with Pylint
+  * Rename build dependency pylint3 to pylint (Closes: #940178)
+  * Switch to debhelper 12
+  * Bump Standards-Version to 4.4.0 (no changes needed)
+
+ -- Benjamin Drung <bdr...@debian.org>  Sat, 14 Sep 2019 15:44:13 +0200
+
 distro-info (0.21) unstable; urgency=medium
 
   [ Benjamin Drung ]
diff -Nru distro-info-0.21/debian/compat distro-info-1.0~deb10u1/debian/compat
--- distro-info-0.21/debian/compat      2018-02-04 15:33:03.000000000 -0400
+++ distro-info-1.0~deb10u1/debian/compat       1969-12-31 20:00:00.000000000 
-0400
@@ -1 +0,0 @@
-11
diff -Nru distro-info-0.21/debian/control distro-info-1.0~deb10u1/debian/control
--- distro-info-0.21/debian/control     2019-02-09 19:29:24.000000000 -0400
+++ distro-info-1.0~deb10u1/debian/control      2021-04-22 11:54:50.000000000 
-0400
@@ -3,10 +3,9 @@
 Priority: optional
 Maintainer: Benjamin Drung <bdr...@debian.org>
 Uploaders: Stefano Rivera <stefa...@debian.org>
-Build-Depends: debhelper (>= 11),
+Build-Depends: debhelper-compat (= 12),
                dh-python,
-               distro-info-data (>= 0.7~),
-               pylint,
+               distro-info-data (>= 0.46~),
                pylint3,
                python-all (>= 2.6.3-3~),
                python-flake8,
@@ -16,17 +15,15 @@
                python3-flake8,
                python3-setuptools,
                shunit2 (>= 2.1.6)
-Standards-Version: 4.3.0
+Standards-Version: 4.5.1
 Rules-Requires-Root: no
 Vcs-Git: https://salsa.debian.org/debian/distro-info.git
 Vcs-Browser: https://salsa.debian.org/debian/distro-info
 
 Package: distro-info
 Architecture: any
-Depends: distro-info-data (>= 0.7~), ${misc:Depends}, ${shlibs:Depends}
+Depends: distro-info-data (>= 0.46~), ${misc:Depends}, ${shlibs:Depends}
 Suggests: shunit2 (>= 2.1.6)
-Breaks: ubuntu-dev-tools (<< 0.133~)
-Replaces: ubuntu-dev-tools (<< 0.127~)
 Description: provides information about the distributions' releases
  Information about all releases of Debian and Ubuntu. The distro-info script
  will give you the codename for e.g. the latest stable release of your
@@ -36,7 +33,8 @@
 Package: libdistro-info-perl
 Architecture: all
 Section: perl
-Depends: distro-info-data, ${misc:Depends}, ${perl:Depends}
+Depends: distro-info-data (>= 0.46~), ${misc:Depends}, ${perl:Depends}
+Multi-Arch: foreign
 Description: information about distributions' releases (Perl module)
  Information about all releases of Debian and Ubuntu.
  .
@@ -46,7 +44,7 @@
 Package: python-distro-info
 Architecture: all
 Section: python
-Depends: distro-info-data, ${misc:Depends}, ${python:Depends}
+Depends: distro-info-data (>= 0.46~), ${misc:Depends}, ${python:Depends}
 Breaks: distro-info (<< 0.3~)
 Replaces: distro-info (<< 0.3~)
 Description: information about distributions' releases (Python module)
@@ -59,7 +57,7 @@
 Package: python3-distro-info
 Architecture: all
 Section: python
-Depends: distro-info-data, ${misc:Depends}, ${python3:Depends}
+Depends: distro-info-data (>= 0.46~), ${misc:Depends}, ${python3:Depends}
 Description: information about distributions' releases (Python 3 module)
  Information about all releases of Debian and Ubuntu.
  .
diff -Nru distro-info-0.21/debian/copyright 
distro-info-1.0~deb10u1/debian/copyright
--- distro-info-0.21/debian/copyright   2018-02-04 15:42:42.000000000 -0400
+++ distro-info-1.0~deb10u1/debian/copyright    2021-04-22 11:54:50.000000000 
-0400
@@ -4,7 +4,7 @@
 
 Files: *
 Copyright: 2009-2018, Benjamin Drung <bdr...@debian.org>
-           2010-2011, Stefano Rivera <stefa...@debian.org>
+           2010-2021, Stefano Rivera <stefa...@debian.org>
 License: ISC
 
 Files: shell/*-distro-info.in shell/distro-info-util.sh
diff -Nru distro-info-0.21/debian/tests/control 
distro-info-1.0~deb10u1/debian/tests/control
--- distro-info-0.21/debian/tests/control       2018-10-11 20:11:26.000000000 
-0400
+++ distro-info-1.0~deb10u1/debian/tests/control        2021-04-22 
11:54:50.000000000 -0400
@@ -7,11 +7,9 @@
 Features: test-name=test-ubuntu-distro-info
 
 Test-Command: cp -r python/distro_info_test python/*-distro-info 
python/setup.py "$AUTOPKGTEST_TMP"; for py in $(py3versions -r 2>/dev/null); do 
cd "$AUTOPKGTEST_TMP"; echo "Testing with $py:"; $py -m unittest discover -v; 
done
-Depends: pylint3, python3-all, python3-distro-info, python3-flake8
+Depends: pylint (>= 2.2.2-2~) | pylint3,
+         python3-all,
+         python3-distro-info,
+         python3-flake8
 Restrictions: allow-stderr
 Features: test-name=python3-unittest
-
-Test-Command: cp -r python/distro_info_test python/*-distro-info 
python/setup.py "$AUTOPKGTEST_TMP"; for py in $(pyversions -r 2>/dev/null); do 
cd "$AUTOPKGTEST_TMP"; echo "Testing with $py:"; $py -m unittest discover -v; 
done
-Depends: pylint, python-all, python-distro-info, python-flake8
-Restrictions: allow-stderr
-Features: test-name=python-unittest
diff -Nru distro-info-0.21/debian-distro-info.c 
distro-info-1.0~deb10u1/debian-distro-info.c
--- distro-info-0.21/debian-distro-info.c       2013-08-02 17:31:52.000000000 
-0400
+++ distro-info-1.0~deb10u1/debian-distro-info.c        2021-04-22 
11:54:50.000000000 -0400
@@ -16,7 +16,7 @@
 
 #define DEBIAN
 #define CSV_NAME "debian"
-#define CSV_HEADER "version,codename,series,created,release,eol"
+#define CSV_HEADER 
"version,codename,series,created,release,eol,eol-lts,eol-elts"
 #define DISTRO_NAME "Debian"
 #define NAME "debian-distro-info"
 
diff -Nru distro-info-0.21/distro-info-util.c 
distro-info-1.0~deb10u1/distro-info-util.c
--- distro-info-0.21/distro-info-util.c 2019-02-09 17:07:26.000000000 -0400
+++ distro-info-1.0~deb10u1/distro-info-util.c  2021-04-22 11:54:50.000000000 
-0400
@@ -38,8 +38,13 @@
 static char *milestones[] = {"created"
                             ,"release"
                             ,"eol"
+#ifdef DEBIAN
+                            ,"eol-lts"
+                            ,"eol-elts"
+#endif
 #ifdef UBUNTU
                             ,"eol-server"
+                            ,"eol-esm"
 #endif
 };
 
@@ -193,6 +198,31 @@
     ;
 }
 
+#ifdef DEBIAN
+static inline bool eol_lts(const date_t *date, const distro_t *distro) {
+    return !distro->milestones[MILESTONE_EOL_LTS] ||
+           date_ge(date, distro->milestones[MILESTONE_EOL_LTS])
+    ;
+}
+
+static inline bool eol_elts(const date_t *date, const distro_t *distro) {
+    return !distro->milestones[MILESTONE_EOL_ELTS] ||
+           date_ge(date, distro->milestones[MILESTONE_EOL_ELTS])
+    ;
+}
+#endif
+
+#ifdef UBUNTU
+static inline bool eol_esm(const date_t *date, const distro_t *distro) {
+    return distro->milestones[MILESTONE_EOL] &&
+           date_ge(date, distro->milestones[MILESTONE_EOL])
+           && (!distro->milestones[MILESTONE_EOL_ESM] ||
+              (distro->milestones[MILESTONE_EOL_ESM] &&
+               date_ge(date, distro->milestones[MILESTONE_EOL_ESM])))
+    ;
+}
+#endif
+
 // Filter callbacks
 
 static bool filter_all(unused(const date_t *date),
@@ -208,6 +238,23 @@
     return created(date, distro) && !eol(date, distro);
 }
 
+#ifdef DEBIAN
+static bool filter_lts_supported(const date_t *date, const distro_t *distro) {
+    return created(date, distro) && eol(date, distro) && !eol_lts(date, 
distro);
+}
+
+static bool filter_elts_supported(const date_t *date, const distro_t *distro) {
+    return created(date, distro) && eol_lts(date, distro) && !eol_elts(date, 
distro);
+}
+#endif
+
+#ifdef UBUNTU
+static bool filter_esm_supported(const date_t *date, const distro_t *distro) {
+    return created(date, distro) && !eol_esm(date, distro) &&
+           strstr(distro->version, "LTS") != NULL;
+}
+#endif
+
 static bool filter_unsupported(const date_t *date, const distro_t *distro) {
     return created(date, distro) && eol(date, distro);
 }
@@ -372,8 +419,13 @@
         free(list->distro->milestones[MILESTONE_CREATED]);
         free(list->distro->milestones[MILESTONE_RELEASE]);
         free(list->distro->milestones[MILESTONE_EOL]);
+#ifdef DEBIAN
+        free(list->distro->milestones[MILESTONE_EOL_LTS]);
+        free(list->distro->milestones[MILESTONE_EOL_ELTS]);
+#endif
 #ifdef UBUNTU
         free(list->distro->milestones[MILESTONE_EOL_SERVER]);
+        free(list->distro->milestones[MILESTONE_EOL_ESM]);
 #endif
         free(list->distro);
         free(list);
@@ -397,9 +449,9 @@
     data = *content = read_full_file(filename);
     line = strsep(&data, "\n");
     lineno = 1;
-    if(unlikely(strcmp(CSV_HEADER, line) != 0)) {
-        fprintf(stderr, NAME ": Header `%s' in file `%s' does not match "
-                "exactly `" CSV_HEADER "'.\n", line, filename);
+    if(unlikely(strncmp(CSV_HEADER, line, strlen(CSV_HEADER)) != 0)) {
+        fprintf(stderr, NAME ": Header `%s' in file `%s' does not start with "
+                "`" CSV_HEADER "'.\n", line, filename);
         failures++;
     }
 
@@ -525,16 +577,23 @@
 #endif
            "  -a  --all              list all known versions\n"
            "  -d  --devel            latest development version\n"
+#ifdef DEBIAN
+           "  -t  --testing          current testing version\n"
+#endif
+           "  -s  --stable           latest stable version\n"
 #ifdef UBUNTU
            "      --lts              latest long term support (LTS) version\n"
 #endif
 #ifdef DEBIAN
            "  -o  --oldstable        latest oldstable version\n"
 #endif
-           "  -s  --stable           latest stable version\n"
            "      --supported        list of all supported stable versions\n"
 #ifdef DEBIAN
-           "  -t  --testing          current testing version\n"
+           "  -l  --lts              list of all LTS supported versions\n"
+           "  -e  --elts             list of all Extended LTS supported 
versions\n"
+#endif
+#ifdef UBUNTU
+           "      --supported-esm    list of all Ubuntu Advantage supported 
stable versions\n"
 #endif
            "      --unsupported      list of all unsupported stable versions\n"
            "  -c  --codename         print the codename (default)\n"
@@ -550,13 +609,20 @@
             "--alias, "
 #endif
             "--all, --devel, "
+#ifdef DEBIAN
+            "--elts, "
+#endif
 #ifdef UBUNTU
-            "--latest, --lts, "
+            "--latest, "
 #endif
+            "--lts, "
 #ifdef DEBIAN
             "--oldstable, "
 #endif
             "--stable, --supported, "
+#ifdef UBUNTU
+            "--supported-esm, "
+#endif
             "--series, "
 #ifdef DEBIAN
             "--testing, "
@@ -590,35 +656,40 @@
 #endif
 
     const struct option long_options[] = {
-        {"help",        no_argument,       NULL, 'h' },
-        {"date",        required_argument, NULL, 'D' },
-        {"series",      required_argument, NULL, 'R' },
-        {"all",         no_argument,       NULL, 'a' },
-        {"days",        optional_argument, NULL, 'y' },
-        {"devel",       no_argument,       NULL, 'd' },
-        {"stable",      no_argument,       NULL, 's' },
-        {"supported",   no_argument,       NULL, 'S' },
-        {"unsupported", no_argument,       NULL, 'U' },
-        {"codename",    no_argument,       NULL, 'c' },
-        {"fullname",    no_argument,       NULL, 'f' },
-        {"release",     no_argument,       NULL, 'r' },
-#ifdef DEBIAN
-        {"alias",       required_argument, NULL, 'A' },
-        {"oldstable",   no_argument,       NULL, 'o' },
-        {"testing",     no_argument,       NULL, 't' },
+        {"help",          no_argument,       NULL, 'h' },
+        {"date",          required_argument, NULL, 'D' },
+        {"series",        required_argument, NULL, 'R' },
+        {"all",           no_argument,       NULL, 'a' },
+        {"days",          optional_argument, NULL, 'y' },
+        {"devel",         no_argument,       NULL, 'd' },
+        {"stable",        no_argument,       NULL, 's' },
+        {"supported",     no_argument,       NULL, 'S' },
+#ifdef UBUNTU
+        {"supported-esm", no_argument,       NULL, 'e' },
+#endif
+        {"unsupported",   no_argument,       NULL, 'U' },
+        {"codename",      no_argument,       NULL, 'c' },
+        {"fullname",      no_argument,       NULL, 'f' },
+        {"release",       no_argument,       NULL, 'r' },
+#ifdef DEBIAN
+        {"alias",         required_argument, NULL, 'A' },
+        {"elts",          no_argument,       NULL, 'e' },
+        {"lts",           no_argument,       NULL, 'l' },
+        {"oldstable",     no_argument,       NULL, 'o' },
+        {"testing",       no_argument,       NULL, 't' },
 #endif
 #ifdef UBUNTU
-        {"latest",      no_argument,       NULL, 'l' },
-        {"lts",         no_argument,       NULL, 'L' },
+        {"latest",        no_argument,       NULL, 'l' },
+        {"lts",           no_argument,       NULL, 'L' },
 #endif
-        {NULL,          0,                 NULL, '\0' }
+        {NULL,            0,                 NULL, '\0' }
     };
 
 #ifdef UBUNTU
     const char *short_options = "hadscrfly::";
 #endif
 #ifdef DEBIAN
-    const char *short_options = "hadscrfoty::";
+    const char *short_options = "hadescrfloty::";
 #endif
 
     // Suppress error messages from getopt_long
@@ -728,6 +799,18 @@
 #endif
 
 #ifdef DEBIAN
+            case 'e':
+                selected_filters++;
+                filter_cb = filter_elts_supported;
+                select_cb = NULL;
+                break;
+
+            case 'l':
+                selected_filters++;
+                filter_cb = filter_lts_supported;
+                select_cb = NULL;
+                break;
+
             case 'o':
                 selected_filters++;
                 filter_cb = filter_oldstable;
@@ -753,6 +836,15 @@
                 select_cb = NULL;
                 break;
 
+#ifdef UBUNTU
+            case 'e':
+                // Only long option --supported-esm is used
+                selected_filters++;
+                filter_cb = filter_esm_supported;
+                select_cb = NULL;
+                break;
+
+#endif
 #ifdef DEBIAN
             case 't':
                 selected_filters++;
diff -Nru distro-info-0.21/distro-info-util.h 
distro-info-1.0~deb10u1/distro-info-util.h
--- distro-info-0.21/distro-info-util.h 2013-08-02 17:31:31.000000000 -0400
+++ distro-info-1.0~deb10u1/distro-info-util.h  2021-04-22 11:54:50.000000000 
-0400
@@ -34,8 +34,13 @@
 enum MILESTONE {MILESTONE_CREATED
                ,MILESTONE_RELEASE
                ,MILESTONE_EOL
+#ifdef DEBIAN
+               ,MILESTONE_EOL_LTS
+               ,MILESTONE_EOL_ELTS
+#endif
 #ifdef UBUNTU
                ,MILESTONE_EOL_SERVER
+               ,MILESTONE_EOL_ESM
 #endif
                ,MILESTONE_COUNT
 };
@@ -70,6 +75,13 @@
 static inline bool created(const date_t *date, const distro_t *distro);
 static inline bool released(const date_t *date, const distro_t *distro);
 static inline bool eol(const date_t *date, const distro_t *distro);
+#ifdef DEBIAN
+static inline bool eol_lts(const date_t *date, const distro_t *distro);
+static inline bool eol_elts(const date_t *date, const distro_t *distro);
+#endif
+#ifdef UBUNTU
+static inline bool eol_esm(const date_t *date, const distro_t *distro);
+#endif
 static inline int milestone_to_index(const char *milestone);
 
 #endif // __DISTRO_INFO_UTIL_H__
diff -Nru distro-info-0.21/doc/ubuntu-distro-info.1 
distro-info-1.0~deb10u1/doc/ubuntu-distro-info.1
--- distro-info-0.21/doc/ubuntu-distro-info.1   2014-05-10 14:53:03.000000000 
-0400
+++ distro-info-1.0~deb10u1/doc/ubuntu-distro-info.1    2021-04-22 
11:54:50.000000000 -0400
@@ -66,6 +66,9 @@
 \fB\-\-supported\fR
 list of all supported stable versions
 .TP
+\fB\-\-supported\-esm\fR
+list of all Ubuntu Advantage supported stable versions
+.TP
 \fB\-\-unsupported\fR
 list of all unsupported stable versions
 .TP
diff -Nru distro-info-0.21/haskell/DebianDistroInfo.hs 
distro-info-1.0~deb10u1/haskell/DebianDistroInfo.hs
--- distro-info-0.21/haskell/DebianDistroInfo.hs        2012-02-25 
11:10:38.000000000 -0400
+++ distro-info-1.0~deb10u1/haskell/DebianDistroInfo.hs 2021-04-22 
11:54:50.000000000 -0400
@@ -21,7 +21,6 @@
 import System.Environment
 import System.Exit
 import System.IO
-import System.Locale
 
 import Text.CSV
 
@@ -47,8 +46,8 @@
 
 onlyOneFilter :: a
 onlyOneFilter = error ("You have to select exactly one of --all, " ++
-                       "--devel, --oldstable, --stable, --supported, " ++
-                       "--testing, --unsupported.")
+                       "--devel, --elts, --lts, --oldstable, --stable, " ++
+                       "--supported, --testing, --unsupported.")
 
 options :: [OptDescr (Options -> IO Options)]
 options =
@@ -61,7 +60,7 @@
         then version
         else debSeries e
     readDate arg opt =
-      return opt { optDate = readTime defaultTimeLocale "%F" arg }
+      return opt { optDate = parseTimeOrError False defaultTimeLocale "%F" arg 
}
     printHelp _ =
       do
         prg <- getProgName
@@ -81,14 +80,18 @@
              "list all known versions"
     , Option "d" ["devel"] (NoArg (setFilter debianDevel))
              "latest development version"
-    , Option "o" ["oldstable"] (NoArg (setFilter debianOldstable))
-             "latest oldstable version"
+    , Option "t" ["testing"] (NoArg (setFilter debianTesting))
+             "current testing version"
     , Option "s" ["stable"] (NoArg (setFilter debianStable))
              "latest stable version"
+    , Option "o" ["oldstable"] (NoArg (setFilter debianOldstable))
+             "latest oldstable version"
     , Option "" ["supported"] (NoArg (setFilter debianSupported))
              "list of all supported stable versions"
-    , Option "t" ["testing"] (NoArg (setFilter debianTesting))
-             "current testing version"
+    , Option "l" ["lts"] (NoArg (setFilter debianSupportedLTS))
+             "list of all LTS supported versions"
+    , Option "e" ["elts"] (NoArg (setFilter debianSupportedELTS))
+             "list of all Extended LTS supported versions"
     , Option "" ["unsupported"] (NoArg (setFilter debianUnsupported))
              "list of all unsupported stable versions"
     , Option "c" ["codename"]
diff -Nru distro-info-0.21/haskell/DistroInfo.hs 
distro-info-1.0~deb10u1/haskell/DistroInfo.hs
--- distro-info-0.21/haskell/DistroInfo.hs      2011-10-11 10:16:17.000000000 
-0400
+++ distro-info-1.0~deb10u1/haskell/DistroInfo.hs       2021-04-22 
11:54:50.000000000 -0400
@@ -20,6 +20,8 @@
                    debianOldstable,
                    debianStable,
                    debianSupported,
+                   debianSupportedLTS,
+                   debianSupportedELTS,
                    debianTesting,
                    debianUnsupported,
                    UbuntuEntry, ubuVersion, ubuSeries, ubuFull,
@@ -29,6 +31,7 @@
                    ubuntuLTS,
                    ubuntuStable,
                    ubuntuSupported,
+                   ubuntuSupportedESM,
                    ubuntuUnsupported,
                   ) where
 
@@ -46,7 +49,9 @@
                                  debSeries :: String,
                                  debCreated :: Day,
                                  debRelease :: Maybe Day,
-                                 debEol :: Maybe Day
+                                 debEol :: Maybe Day,
+                                 debEolLTS :: Maybe Day,
+                                 debEolELTS :: Maybe Day
                                } deriving(Eq, Show)
 
 -- | Represents one Ubuntu release data set
@@ -57,7 +62,8 @@
                                  ubuCreated :: Day,
                                  ubuRelease :: Day,
                                  ubuEol :: Day,
-                                 ubuEolServer :: Maybe Day
+                                 ubuEolServer :: Maybe Day,
+                                 ubuEolESM :: Maybe Day
                                } deriving(Eq, Show)
 
 -- | Splits a string by a given character (similar to the Python split 
function)
@@ -104,6 +110,7 @@
                   (convertDate $ m ! "created") (convertDate $ m ! "release")
                   (convertDate $ m ! "eol")
                   (maybeDate $ Map.lookup "eol-server" m)
+                  (maybeDate $ Map.lookup "eol-esm" m)
 
 -- | Converts a given CSV data into a list of Debian entries
 debianEntry :: CSV -> [DebianEntry]
@@ -117,6 +124,8 @@
                   (convertDate $ m ! "created")
                   (maybeDate $ Map.lookup "release" m)
                   (maybeDate $ Map.lookup "eol" m)
+                  (maybeDate $ Map.lookup "eol-lts" m)
+                  (maybeDate $ Map.lookup "eol-elts" m)
 
 -------------------
 -- Debian Filter --
@@ -161,6 +170,22 @@
     isSupported DebianEntry { debCreated = created, debEol = eol } =
       date >= created && maybe True (date <=) eol
 
+-- | Get list of all LTS supported distributions based on the given date.
+debianSupportedLTS :: Day -> [DebianEntry] -> [DebianEntry]
+debianSupportedLTS date = filter isSupportedLTS
+  where
+    isSupportedLTS DebianEntry { debCreated = created, debEol = eol,
+                                 debEolLTS = eol_lts } =
+      date >= created && maybe False (date >) eol && maybe False (date <=) 
eol_lts
+
+-- | Get list of all ELTS supported distributions based on the given date.
+debianSupportedELTS :: Day -> [DebianEntry] -> [DebianEntry]
+debianSupportedELTS date = filter isSupportedELTS
+  where
+    isSupportedELTS DebianEntry { debCreated = created, debEolLTS = eol_lts,
+                                  debEolELTS = eol_elts } =
+      date >= created && maybe False (date >) eol_lts && maybe False (date <=) 
eol_elts
+
 -- | Get latest testing Debian distribution based on the given date.
 debianTesting :: Day -> [DebianEntry] -> [DebianEntry]
 debianTesting date = filter isUnreleased
@@ -225,6 +250,13 @@
                               ubuEolServer = eolServer } =
       date >= created && (date <= eol || maybe False (date <=) eolServer)
 
+-- | Get list of all ESM supported distributions based on the given date.
+ubuntuSupportedESM :: Day -> [UbuntuEntry] -> [UbuntuEntry]
+ubuntuSupportedESM date = filter isSupportedESM
+  where
+    isSupportedESM UbuntuEntry { ubuCreated = created, ubuEolESM = eolESM } =
+      date >= created && maybe False (date <=) eolESM
+
 -- | Get list of all unsupported distributions based on the given date.
 ubuntuUnsupported :: Day -> [UbuntuEntry] -> [UbuntuEntry]
 ubuntuUnsupported date = filter isUnsupported
diff -Nru distro-info-0.21/haskell/TestDistroInfo.hs 
distro-info-1.0~deb10u1/haskell/TestDistroInfo.hs
--- distro-info-0.21/haskell/TestDistroInfo.hs  2012-03-22 19:07:08.000000000 
-0400
+++ distro-info-1.0~deb10u1/haskell/TestDistroInfo.hs   2021-04-22 
11:54:50.000000000 -0400
@@ -26,6 +26,10 @@
 
 date1 :: Day
 date1 = fromGregorian 2011 01 10
+date2 :: Day
+date2 = fromGregorian 2016 02 28
+date3 :: Day
+date3 = fromGregorian 2020 06 29
 
 ------------------
 -- Debian tests --
@@ -62,6 +66,18 @@
     expected = ["lenny", "squeeze", "sid", "experimental"]
     result = map debSeries $ debianSupported date1 d
 
+testDebianSupportedLTS :: [DebianEntry] -> Test
+testDebianSupportedLTS d = TestCase (assertEqual "Debian LTS" expected result)
+  where
+    expected = ["squeeze"]
+    result = map debSeries $ debianSupportedLTS date2 d
+
+testDebianSupportedELTS :: [DebianEntry] -> Test
+testDebianSupportedELTS d = TestCase (assertEqual "Debian ELTS" expected 
result)
+  where
+    expected = ["wheezy"]
+    result = map debSeries $ debianSupportedELTS date3 d
+
 testDebianTesting :: [DebianEntry] -> Test
 testDebianTesting d = TestCase (assertEqual "Debian testing" expected result)
   where
@@ -111,6 +127,12 @@
     expected = ["dapper", "hardy", "karmic", "lucid", "maverick", "natty"]
     result = map ubuSeries $ ubuntuSupported date1 u
 
+testUbuntuSupportedESM :: [UbuntuEntry] -> Test
+testUbuntuSupportedESM u = TestCase (assertEqual "Ubuntu ESM" expected result)
+  where
+    expected = ["precise", "trusty", "xenial"]
+    result = map ubuSeries $ ubuntuSupportedESM date2 u
+
 testUbuntuUnsupported :: [UbuntuEntry] -> Test
 testUbuntuUnsupported u = TestCase (assertEqual "Ubuntu unsupported" expected 
result)
   where
@@ -126,6 +148,8 @@
 tests d u = TestList [
     testDebianAll d,
     testDebianDevel d,
+    testDebianSupportedLTS d,
+    testDebianSupportedELTS d,
     testDebianOldstable d,
     testDebianStable d,
     testDebianSupported d,
@@ -136,6 +160,7 @@
     testUbuntuLTS u,
     testUbuntuStable u,
     testUbuntuSupported u,
+    testUbuntuSupportedESM u,
     testUbuntuUnsupported u
   ]
 
diff -Nru distro-info-0.21/haskell/UbuntuDistroInfo.hs 
distro-info-1.0~deb10u1/haskell/UbuntuDistroInfo.hs
--- distro-info-0.21/haskell/UbuntuDistroInfo.hs        2012-02-25 
11:10:20.000000000 -0400
+++ distro-info-1.0~deb10u1/haskell/UbuntuDistroInfo.hs 2021-04-22 
11:54:50.000000000 -0400
@@ -21,7 +21,6 @@
 import System.Environment
 import System.Exit
 import System.IO
-import System.Locale
 
 import Text.CSV
 
@@ -47,13 +46,14 @@
 
 onlyOneFilter :: a
 onlyOneFilter = error ("You have to select exactly one of --all, --devel, " ++
-                       "--lts, --stable, --supported, --unsupported.")
+                       "--lts, --stable, --supported, --supported-esm, " ++
+                       "--unsupported.")
 
 options :: [OptDescr (Options -> IO Options)]
 options =
   let
     readDate arg opt =
-      return opt { optDate = readTime defaultTimeLocale "%F" arg }
+      return opt { optDate = parseTimeOrError False defaultTimeLocale "%F" arg 
}
     printHelp _ =
       do
         prg <- getProgName
@@ -73,12 +73,14 @@
              "list all known versions"
     , Option "d" ["devel"] (NoArg (setFilter ubuntuDevel))
              "latest development version"
-    , Option "" ["lts"] (NoArg (setFilter ubuntuLTS))
-             "latest long term support (LTS) version"
     , Option "s" ["stable"] (NoArg (setFilter ubuntuStable))
              "latest stable version"
+    , Option "" ["lts"] (NoArg (setFilter ubuntuLTS))
+             "latest long term support (LTS) version"
     , Option "" ["supported"] (NoArg (setFilter ubuntuSupported))
              "list of all supported stable versions"
+    , Option "" ["supported-esm"] (NoArg (setFilter ubuntuSupportedESM))
+             "list of all Ubuntu Advantage supported stable versions"
     , Option "" ["unsupported"] (NoArg (setFilter ubuntuUnsupported))
              "list of all unsupported stable versions"
     , Option "c" ["codename"]
diff -Nru distro-info-0.21/Makefile distro-info-1.0~deb10u1/Makefile
--- distro-info-0.21/Makefile   2018-10-11 20:11:26.000000000 -0400
+++ distro-info-1.0~deb10u1/Makefile    2021-04-22 11:54:50.000000000 -0400
@@ -37,7 +37,7 @@
        cd perl && ./test.pl
 
 test-python:
-       $(foreach python,$(shell pyversions -r && py3versions -r),cd python && 
$(python) setup.py test$(\n))
+       $(foreach python,$(shell py3versions -r),cd python && $(python) 
setup.py test$(\n))
 
 clean:
        rm -rf debian-distro-info ubuntu-distro-info python/build 
python/*.egg-info python/.pylint.d
diff -Nru distro-info-0.21/perl/Debian/DistroInfo.pm 
distro-info-1.0~deb10u1/perl/Debian/DistroInfo.pm
--- distro-info-0.21/perl/Debian/DistroInfo.pm  2019-02-09 17:15:09.000000000 
-0400
+++ distro-info-1.0~deb10u1/perl/Debian/DistroInfo.pm   2021-04-22 
11:54:50.000000000 -0400
@@ -77,7 +77,8 @@
             for my $col (@header) {
                 $row{$col} = shift(@raw_row) or undef;
             }
-            for my $col ('created', 'release', 'eol', 'eol-server') {
+            for my $col ('created', 'release', 'eol', 'eol-esm', 'eol-lts',
+                         'eol-elts', 'eol-server') {
                 if(defined($row{$col})) {
                     $row{$col} = Debian::DistroInfo::convert_date($row{$col});
                 }
@@ -249,6 +250,32 @@
         return @distros;
     }
 
+    sub supported_lts {
+        my ($self, $date) = @_;
+        $date = $self->{'date'} if (!defined($date));
+        my @distros;
+        for my $row ($self->_avail($date)) {
+            if (defined($row->{'eol'}) && $date > $row->{'eol'}
+                    && defined($row->{'eol-lts'}) && $date <= 
$row->{'eol-lts'}) {
+                push(@distros, $row->{'series'});
+            }
+        }
+        return @distros;
+    }
+
+    sub supported_elts {
+        my ($self, $date) = @_;
+        $date = $self->{'date'} if (!defined($date));
+        my @distros;
+        for my $row ($self->_avail($date)) {
+            if (defined($row->{'eol-lts'}) && $date > $row->{'eol-lts'}
+                    && defined($row->{'eol-elts'}) && $date <= 
$row->{'eol-elts'}) {
+                push(@distros, $row->{'series'});
+            }
+        }
+        return @distros;
+    }
+
     sub testing {
         my ($self, $date) = @_;
         $date = $self->{'date'} if (!defined($date));
@@ -327,6 +354,18 @@
                 push(@distros, $row->{'series'});
             }
         }
+        return @distros;
+    }
+
+    sub supported_esm {
+        my ($self, $date) = @_;
+        $date = $self->{'date'} if (!defined($date));
+        my @distros;
+        for my $row ($self->_avail($date)) {
+            if (defined($row->{'eol-esm'}) && $date <= $row->{'eol-esm'}) {
+                push(@distros, $row->{'series'});
+            }
+        }
         return @distros;
     }
 }
diff -Nru distro-info-0.21/perl/test.pl distro-info-1.0~deb10u1/perl/test.pl
--- distro-info-0.21/perl/test.pl       2019-02-09 17:15:09.000000000 -0400
+++ distro-info-1.0~deb10u1/perl/test.pl        2021-04-22 11:54:50.000000000 
-0400
@@ -1,5 +1,5 @@
 #!/usr/bin/perl
-# Copyright (C) 2011-2012, Stefano Rivera <stefa...@debian.org>
+# Copyright (C) 2011-2019, Stefano Rivera <stefa...@debian.org>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -16,7 +16,7 @@
 use strict;
 use warnings;
 
-use Test::Simple tests => 32;
+use Test::Simple tests => 35;
 
 use lib '.';
 use Debian::DistroInfo;
@@ -55,35 +55,47 @@
 
 # Test DistroInfo:
 my @expected = ();
-my $date = Debian::DistroInfo::convert_date('2011-01-10');
+my $date1 = Debian::DistroInfo::convert_date('2011-01-10');
+my $date2 = Debian::DistroInfo::convert_date('2016-02-28');
+my $date3 = Debian::DistroInfo::convert_date('2020-06-29');
 
 my $deb = DebianDistroInfo->new();
 @all = ('buzz', 'rex', 'bo', 'hamm', 'slink', 'potato', 'woody', 'sarge',
            'etch', 'lenny', 'squeeze', 'sid', 'experimental');
-@returned = $deb->all($date);
+@returned = $deb->all($date1);
 ok(unique(\@all, \@returned) == 0, 'Debian all');
 
-ok($deb->devel($date) eq 'sid', 'Debian devel');
-ok($deb->old($date) eq 'etch', 'Debian oldstable');
-ok($deb->stable($date) eq 'lenny', 'Debian stable');
-ok($deb->testing($date) eq 'squeeze', 'Debian testing');
+ok($deb->devel($date1) eq 'sid', 'Debian devel');
+ok($deb->old($date1) eq 'etch', 'Debian oldstable');
+ok($deb->stable($date1) eq 'lenny', 'Debian stable');
+ok($deb->testing($date1) eq 'squeeze', 'Debian testing');
 ok($deb->valid('sid'), 'Debian valid');
 ok($deb->valid('stable'), 'Debian valid');
 ok(!$deb->valid('foobar'), 'Debian invalid');
 
 @expected = ('lenny', 'squeeze', 'sid', 'experimental');
-@returned = $deb->supported($date);
+@returned = $deb->supported($date1);
 ok(symmetric_difference(\@expected, \@returned) == 0,
    'Debian supported');
 
+@expected = ('squeeze');
+@returned = $deb->supported_lts($date2);
+ok(symmetric_difference(\@expected, \@returned) == 0,
+   'Debian LTS');
+
+@expected = ('wheezy');
+@returned = $deb->supported_elts($date3);
+ok(symmetric_difference(\@expected, \@returned) == 0,
+   'Debian ELTS');
+
 @expected = ('buzz', 'rex', 'bo', 'hamm', 'slink', 'potato', 'woody', 'sarge',
              'etch');
-@returned = $deb->unsupported($date);
+@returned = $deb->unsupported($date1);
 ok(symmetric_difference(\@expected, \@returned) == 0,
    'Debian unsupported');
 
 ok(!defined($deb->codename('foo')), 'Debian codename, invalid');
-ok($deb->codename('testing', $date) eq $deb->testing($date),
+ok($deb->codename('testing', $date1) eq $deb->testing($date1),
    'Debian codename');
 
 ok(!defined($deb->version('foo')), 'Debian version, invalid');
@@ -92,15 +104,15 @@
 my $ubu = UbuntuDistroInfo->new();
 @all = ('warty', 'hoary', 'breezy', 'dapper', 'edgy', 'feisty', 'gutsy',
         'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid', 'maverick', 'natty');
-@returned = $ubu->all($date);
+@returned = $ubu->all($date1);
 ok(unique(\@all, \@returned) == 0, 'Ubuntu all');
 
 ok($ubu->version('Maverick Meerkat') eq '10.10', 'Ubuntu version');
 ok($ubu->version('lucid') eq '10.04 LTS', 'Ubuntu LTS version');
 
-ok($ubu->devel($date) eq 'natty', 'Ubuntu devel');
-ok($ubu->lts($date) eq 'lucid', 'Ubuntu LTS');
-ok($ubu->stable($date) eq 'maverick', 'Ubuntu stable');
+ok($ubu->devel($date1) eq 'natty', 'Ubuntu devel');
+ok($ubu->lts($date1) eq 'lucid', 'Ubuntu LTS');
+ok($ubu->stable($date1) eq 'maverick', 'Ubuntu stable');
 ok($ubu->valid('lucid'), 'Ubuntu valid');
 ok(!$ubu->valid(42), 'Ubuntu invalid');
 ok($ubu->is_lts('lucid'), 'Ubuntu is_lts');
@@ -108,13 +120,18 @@
 ok(!$ubu->is_lts('warty'), 'Ubuntu !is_lts');
 
 @expected = ('dapper', 'hardy', 'karmic', 'lucid', 'maverick', 'natty');
-@returned = $ubu->supported($date);
+@returned = $ubu->supported($date1);
 ok(symmetric_difference(\@expected, \@returned) == 0,
    'Ubuntu supported');
 
+@expected = ('precise', 'trusty', 'xenial');
+@returned = $ubu->supported_esm($date2);
+ok(symmetric_difference(\@expected, \@returned) == 0,
+   'Ubuntu ESM');
+
 @expected = ('warty', 'hoary', 'breezy', 'edgy', 'feisty', 'gutsy', 'intrepid',
              'jaunty');
-@returned = $ubu->unsupported($date);
+@returned = $ubu->unsupported($date1);
 ok(symmetric_difference(\@expected, \@returned) == 0,
    'Ubuntu unsupported');
 
diff -Nru distro-info-0.21/python/debian-distro-info 
distro-info-1.0~deb10u1/python/debian-distro-info
--- distro-info-0.21/python/debian-distro-info  2018-11-11 17:08:04.000000000 
-0400
+++ distro-info-1.0~deb10u1/python/debian-distro-info   2021-04-22 
11:54:50.000000000 -0400
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 # Copyright (C) 2009-2011, Benjamin Drung <bdr...@debian.org>
 #
@@ -38,24 +38,29 @@
                         help="list all known versions")
     parser.add_argument("-d", "--devel", dest="devel", action="store_true",
                         help="latest development version")
-    parser.add_argument("-o", "--old", dest="old", action="store_true",
-                        help="latest old (stable) version")
+    parser.add_argument("-t", "--testing", dest="testing", action="store_true",
+                        help="current testing version")
     parser.add_argument("-s", "--stable", dest="stable", action="store_true",
                         help="latest stable version")
+    parser.add_argument("-o", "--old", dest="old", action="store_true",
+                        help="latest old (stable) version")
     parser.add_argument("--supported", dest="supported", action="store_true",
                         help="list of all supported stable versions")
-    parser.add_argument("-t", "--testing", dest="testing", action="store_true",
-                        help="current testing version")
+    parser.add_argument("-l", "--lts", dest="lts", action="store_true",
+                        help="list of all LTS supported stable versions")
+    parser.add_argument("-e", "--elts", dest="elts", action="store_true",
+                        help="list of all ELTS supported stable versions")
     parser.add_argument("--unsupported", dest="unsupported",
                         help="list of all unsupported stable versions")
 
     args = parser.parse_args()
 
-    versions = [args.all, args.devel, args.old, args.stable,
-                args.supported, args.testing, args.unsupported]
+    versions = [args.all, args.devel, args.lts, args.elts, args.old,
+                args.stable, args.supported, args.testing, args.unsupported]
     if len([x for x in versions if x]) != 1:
-        parser.error("You have to select exactly one of --all, --devel, --old, 
"
-                     "--stable, --supported, --testing, --unsupported.")
+        parser.error("You have to select exactly one of --all, --devel, "
+                     "--elts, --lts, --old, --stable, --supported, --testing, "
+                     "--unsupported.")
 
     if args.date is not None:
         try:
@@ -67,6 +72,7 @@
 
 
 def main():
+    # pylint: disable=too-many-branches
     args = parse_args()
     if args.all:
         for distro in DebianDistroInfo().all:
@@ -80,6 +86,12 @@
     elif args.supported:
         for distro in DebianDistroInfo().supported(args.date):
             sys.stdout.write(distro + "\n")
+    elif args.lts:
+        for distro in DebianDistroInfo().lts_supported(args.date):
+            sys.stdout.write(distro + "\n")
+    elif args.elts:
+        for distro in DebianDistroInfo().elts_supported(args.date):
+            sys.stdout.write(distro + "\n")
     elif args.testing:
         sys.stdout.write(DebianDistroInfo().testing(args.date) + "\n")
     elif args.unsupported:
diff -Nru distro-info-0.21/python/distro_info.py 
distro-info-1.0~deb10u1/python/distro_info.py
--- distro-info-0.21/python/distro_info.py      2019-02-09 17:18:08.000000000 
-0400
+++ distro-info-1.0~deb10u1/python/distro_info.py       2021-04-22 
11:54:50.000000000 -0400
@@ -48,18 +48,31 @@
     """Distribution data outdated."""
 
     def __init__(self):
-        super(DistroDataOutdated, self).__init__(
-            "Distribution data outdated. "
-            "Please check for an update for distro-info-data. See "
-            "/usr/share/doc/distro-info-data/README.Debian for details.")
+        super().__init__(
+            "Distribution data outdated. Please check for an update for 
distro-info-data. "
+            "See /usr/share/doc/distro-info-data/README.Debian for details."
+        )
 
 
 class DistroRelease(object):
     """Represents a distributions release"""
+
     # pylint: disable=too-few-public-methods
+    # pylint: disable=too-many-instance-attributes
 
-    def __init__(self, version, codename, series, created=None, release=None, 
eol=None,
-                 eol_server=None):
+    def __init__(
+            self,
+            version,
+            codename,
+            series,
+            created=None,
+            release=None,
+            eol=None,
+            eol_esm=None,
+            eol_lts=None,
+            eol_elts=None,
+            eol_server=None,
+    ):
         # pylint: disable=too-many-arguments
         self.version = version
         self.codename = codename
@@ -67,12 +80,18 @@
         self.created = created
         self.release = release
         self.eol = eol
+        self.eol_lts = eol_lts
+        self.eol_elts = eol_elts
+        self.eol_esm = eol_esm
         self.eol_server = eol_server
 
     def is_supported(self, date):
         """Check whether this release is supported on the given date."""
-        return date >= self.created and (self.eol is None or date <= self.eol 
or (
-            self.eol_server is not None and date <= self.eol_server))
+        return date >= self.created and (
+            self.eol is None
+            or date <= self.eol
+            or (self.eol_server is not None and date <= self.eol_server)
+        )
 
 
 def _get_date(row, column):
@@ -91,9 +110,18 @@
         csv_reader = csv.DictReader(csvfile)
         self._releases = []
         for row in csv_reader:
-            release = DistroRelease(row['version'], row['codename'], 
row['series'],
-                                    _get_date(row, 'created'), _get_date(row, 
'release'),
-                                    _get_date(row, 'eol'), _get_date(row, 
'eol-server'))
+            release = DistroRelease(
+                row["version"],
+                row["codename"],
+                row["series"],
+                _get_date(row, "created"),
+                _get_date(row, "release"),
+                _get_date(row, "eol"),
+                _get_date(row, "eol-esm"),
+                _get_date(row, "eol-lts"),
+                _get_date(row, "eol-elts"),
+                _get_date(row, "eol-server"),
+            )
             self._releases.append(release)
         csvfile.close()
         self._date = datetime.date.today()
@@ -127,8 +155,11 @@
         """Get latest development distribution based on the given date."""
         if date is None:
             date = self._date
-        distros = [x for x in self._avail(date) if x.release is None or
-                   (date < x.release and (x.eol is None or date <= x.eol))]
+        distros = [
+            x
+            for x in self._avail(date)
+            if x.release is None or (date < x.release and (x.eol is None or 
date <= x.eol))
+        ]
         if not distros:
             raise DistroDataOutdated()
         return self._format(result, distros[-1])
@@ -144,15 +175,20 @@
         if format_string == "release":
             return release.version
 
-        raise ValueError("Only codename, fullname, object, and release are 
allowed "
-                         "result values, but not '" + format_string + "'.")
+        raise ValueError(
+            "Only codename, fullname, object, and release are allowed "
+            "result values, but not '" + format_string + "'."
+        )
 
     def stable(self, date=None, result="codename"):
         """Get latest stable distribution based on the given date."""
         if date is None:
             date = self._date
-        distros = [x for x in self._avail(date) if x.release is not None and
-                   date >= x.release and (x.eol is None or date <= x.eol)]
+        distros = [
+            x
+            for x in self._avail(date)
+            if x.release is not None and date >= x.release and (x.eol is None 
or date <= x.eol)
+        ]
         if not distros:
             raise DistroDataOutdated()
         return self._format(result, distros[-1])
@@ -170,8 +206,7 @@
         if date is None:
             date = self._date
         supported = self.supported(date)
-        distros = [self._format(result, x) for x in self._avail(date)
-                   if x.series not in supported]
+        distros = [self._format(result, x) for x in self._avail(date) if 
x.series not in supported]
         return distros
 
 
@@ -179,7 +214,7 @@
     """provides information about Debian's distributions"""
 
     def __init__(self):
-        super(DebianDistroInfo, self).__init__("Debian")
+        super().__init__("Debian")
 
     def codename(self, release, date=None, default=None):
         """Map 'unstable', 'testing', etc. to their codenames."""
@@ -199,8 +234,11 @@
         """Get latest development distribution based on the given date."""
         if date is None:
             date = self._date
-        distros = [x for x in self._avail(date) if x.release is None or
-                   (date < x.release and (x.eol is None or date <= x.eol))]
+        distros = [
+            x
+            for x in self._avail(date)
+            if x.release is None or (date < x.release and (x.eol is None or 
date <= x.eol))
+        ]
         if len(distros) < 2:
             raise DistroDataOutdated()
         return self._format(result, distros[-2])
@@ -209,51 +247,85 @@
         """Get old (stable) Debian distribution based on the given date."""
         if date is None:
             date = self._date
-        distros = [x for x in self._avail(date)
-                   if x.release is not None and date >= x.release]
+        distros = [x for x in self._avail(date) if x.release is not None and 
date >= x.release]
         if len(distros) < 2:
             raise DistroDataOutdated()
         return self._format(result, distros[-2])
 
     def supported(self, date=None, result="codename"):
         """Get list of all supported Debian distributions based on the given
-           date."""
+        date."""
         if date is None:
             date = self._date
-        distros = [self._format(result, x) for x in self._avail(date)
-                   if x.eol is None or date <= x.eol]
+        distros = [
+            self._format(result, x) for x in self._avail(date) if x.eol is 
None or date <= x.eol
+        ]
+        return distros
+
+    def lts_supported(self, date=None, result="codename"):
+        """Get list of all LTS supported Debian distributions based on the 
given
+        date."""
+        if date is None:
+            date = self._date
+        distros = [
+            self._format(result, x)
+            for x in self._avail(date)
+            if (x.eol is not None and date > x.eol)
+            and (x.eol_lts is not None and date <= x.eol_lts)
+        ]
+        return distros
+
+    def elts_supported(self, date=None, result="codename"):
+        """Get list of all Extended LTS supported Debian distributions based on
+        the given date."""
+        if date is None:
+            date = self._date
+        distros = [
+            self._format(result, x)
+            for x in self._avail(date)
+            if (x.eol_lts is not None and date > x.eol_lts)
+            and (x.eol_elts is not None and date <= x.eol_elts)
+        ]
         return distros
 
     def testing(self, date=None, result="codename"):
         """Get latest testing Debian distribution based on the given date."""
         if date is None:
             date = self._date
-        distros = [x for x in self._avail(date) if (x.release is None and 
x.version) or
-                   (x.release is not None and date < x.release and
-                    (x.eol is None or date <= x.eol))]
+        distros = [
+            x
+            for x in self._avail(date)
+            if (x.release is None and x.version)
+            or (x.release is not None and date < x.release and (x.eol is None 
or date <= x.eol))
+        ]
         if not distros:
             raise DistroDataOutdated()
         return self._format(result, distros[-1])
 
     def valid(self, codename):
         """Check if the given codename is known."""
-        return (DistroInfo.valid(self, codename) or
-                codename in ["unstable", "testing", "stable", "oldstable"])
+        return DistroInfo.valid(self, codename) or codename in [
+            "unstable",
+            "testing",
+            "stable",
+            "oldstable",
+        ]
 
 
 class UbuntuDistroInfo(DistroInfo):
     """provides information about Ubuntu's distributions"""
 
     def __init__(self):
-        super(UbuntuDistroInfo, self).__init__("Ubuntu")
+        super().__init__("Ubuntu")
 
     def lts(self, date=None, result="codename"):
         """Get latest long term support (LTS) Ubuntu distribution based on the
-           given date."""
+        given date."""
         if date is None:
             date = self._date
-        distros = [x for x in self._releases if x.version.find("LTS") >= 0 and
-                   x.release <= date <= x.eol]
+        distros = [
+            x for x in self._releases if x.version.find("LTS") >= 0 and 
x.release <= date <= x.eol
+        ]
         if not distros:
             raise DistroDataOutdated()
         return self._format(result, distros[-1])
@@ -267,10 +339,24 @@
 
     def supported(self, date=None, result="codename"):
         """Get list of all supported Ubuntu distributions based on the given
-           date."""
+        date."""
+        if date is None:
+            date = self._date
+        distros = [
+            self._format(result, x)
+            for x in self._avail(date)
+            if date <= x.eol or (x.eol_server is not None and date <= 
x.eol_server)
+        ]
+        return distros
+
+    def supported_esm(self, date=None, result="codename"):
+        """Get list of all ESM supported Ubuntu distributions based on the
+        given date."""
         if date is None:
             date = self._date
-        distros = [self._format(result, x) for x in self._avail(date)
-                   if date <= x.eol or
-                   (x.eol_server is not None and date <= x.eol_server)]
+        distros = [
+            self._format(result, x)
+            for x in self._avail(date)
+            if x.eol_esm is not None and date <= x.eol_esm
+        ]
         return distros
diff -Nru distro-info-0.21/python/distro_info_test/__init__.py 
distro-info-1.0~deb10u1/python/distro_info_test/__init__.py
--- distro-info-0.21/python/distro_info_test/__init__.py        2018-11-11 
17:03:58.000000000 -0400
+++ distro-info-1.0~deb10u1/python/distro_info_test/__init__.py 2021-04-22 
11:54:50.000000000 -0400
@@ -24,7 +24,7 @@
 def get_source_files():
     """Return a list of sources files/directories (to check with 
flake8/pylint)"""
     scripts = ["debian-distro-info", "ubuntu-distro-info"]
-    modules = ["distro_info_test"]
+    modules = []
     py_files = ["distro_info.py", "setup.py"]
 
     files = []
@@ -41,8 +41,9 @@
         if is_script:
             with open(code_file, "rb") as script_file:
                 shebang = script_file.readline().decode("utf-8")
-            if ((sys.version_info[0] == 3 and "python3" in shebang)
-                    or ("python" in shebang and "python3" not in shebang)):
+            if (sys.version_info[0] == 3 and "python3" in shebang) or (
+                "python" in shebang and "python3" not in shebang
+            ):
                 files.append(code_file)
         else:
             files.append(code_file)
diff -Nru distro-info-0.21/python/distro_info_test/test_distro_info.py 
distro-info-1.0~deb10u1/python/distro_info_test/test_distro_info.py
--- distro-info-0.21/python/distro_info_test/test_distro_info.py        
2019-02-09 17:15:09.000000000 -0400
+++ distro-info-1.0~deb10u1/python/distro_info_test/test_distro_info.py 
2021-04-22 11:54:50.000000000 -0400
@@ -31,9 +31,21 @@
 
     def test_all(self):
         """Test: List all known Debian distributions."""
-        all_distros = set(["buzz", "rex", "bo", "hamm", "slink", "potato",
-                           "woody", "sarge", "etch", "lenny", "squeeze", "sid",
-                           "experimental"])
+        all_distros = {
+            "buzz",
+            "rex",
+            "bo",
+            "hamm",
+            "slink",
+            "potato",
+            "woody",
+            "sarge",
+            "etch",
+            "lenny",
+            "squeeze",
+            "sid",
+            "experimental",
+        }
         self.assertEqual(all_distros - set(self._distro_info.all), set())
 
     def test_devel(self):
@@ -50,8 +62,19 @@
 
     def test_supported(self):
         """Test: List all supported Debian distribution."""
-        self.assertEqual(self._distro_info.supported(self._date),
-                         ["lenny", "squeeze", "sid", "experimental"])
+        self.assertEqual(
+            self._distro_info.supported(self._date), ["lenny", "squeeze", 
"sid", "experimental"]
+        )
+
+    def test_lts_supported(self):
+        """Test: List all LTS supported Debian distribution."""
+        date = datetime.date(2016, 2, 28)
+        self.assertEqual(self._distro_info.lts_supported(date), ["squeeze"])
+
+    def test_elts_supported(self):
+        """Test: List all ELTS supported Debian distribution."""
+        date = datetime.date(2020, 6, 29)
+        self.assertEqual(self._distro_info.elts_supported(date), ["wheezy"])
 
     def test_testing(self):
         """Test: Get latest testing Debian distribution."""
@@ -65,41 +88,38 @@
 
     def test_unsupported(self):
         """Test: List all unsupported Debian distribution."""
-        unsupported = ["buzz", "rex", "bo", "hamm", "slink", "potato", "woody",
-                       "sarge", "etch"]
+        unsupported = ["buzz", "rex", "bo", "hamm", "slink", "potato", 
"woody", "sarge", "etch"]
         self.assertEqual(self._distro_info.unsupported(self._date), 
unsupported)
 
     def test_codename(self):
         """Test: Codename decoding"""
-        self.assertIsNone(self._distro_info.codename('foobar'))
-        self.assertEqual(self._distro_info.codename('testing', self._date),
-                         self._distro_info.testing(self._date))
+        self.assertIsNone(self._distro_info.codename("foobar"))
+        self.assertEqual(
+            self._distro_info.codename("testing", self._date),
+            self._distro_info.testing(self._date),
+        )
 
     def test_version(self):
         """Test: Version decoding"""
-        self.assertIsNone(self._distro_info.version('foobar'))
-        self.assertEqual(self._distro_info.version('lenny'), '5.0')
+        self.assertIsNone(self._distro_info.version("foobar"))
+        self.assertEqual(self._distro_info.version("lenny"), "5.0")
 
     def test_codename_result(self):
         """Test: Check result set to codename."""
         self.assertEqual(self._distro_info.old(self._date, "codename"), "etch")
-        self.assertEqual(self._distro_info.devel(self._date, 
result="codename"),
-                         "sid")
+        self.assertEqual(self._distro_info.devel(self._date, 
result="codename"), "sid")
 
     def test_fullname(self):
         """Test: Check result set to fullname."""
-        self.assertEqual(self._distro_info.stable(self._date, "fullname"),
-                         'Debian 5.0 "Lenny"')
+        self.assertEqual(self._distro_info.stable(self._date, "fullname"), 
'Debian 5.0 "Lenny"')
         result = self._distro_info.testing(self._date, result="fullname")
         self.assertEqual(result, 'Debian 6.0 "Squeeze"')
 
     def test_release(self):
         """Test: Check result set to release."""
         self.assertEqual(self._distro_info.devel(self._date, "release"), "")
-        self.assertEqual(self._distro_info.testing(self._date, "release"),
-                         "6.0")
-        self.assertEqual(self._distro_info.stable(self._date, 
result="release"),
-                         "5.0")
+        self.assertEqual(self._distro_info.testing(self._date, "release"), 
"6.0")
+        self.assertEqual(self._distro_info.stable(self._date, 
result="release"), "5.0")
 
 
 class UbuntuDistroInfoTestCase(unittest.TestCase):  # pylint: 
disable=too-many-public-methods
@@ -111,9 +131,22 @@
 
     def test_all(self):
         """Test: List all known Ubuntu distributions."""
-        all_distros = set(["warty", "hoary", "breezy", "dapper", "edgy",
-                           "feisty", "gutsy", "hardy", "intrepid", "jaunty",
-                           "karmic", "lucid", "maverick", "natty"])
+        all_distros = {
+            "warty",
+            "hoary",
+            "breezy",
+            "dapper",
+            "edgy",
+            "feisty",
+            "gutsy",
+            "hardy",
+            "intrepid",
+            "jaunty",
+            "karmic",
+            "lucid",
+            "maverick",
+            "natty",
+        }
         self.assertEqual(all_distros - set(self._distro_info.all), set())
 
     def test_devel(self):
@@ -135,16 +168,13 @@
 
     def test_unsupported(self):
         """Test: List all unsupported Ubuntu distributions."""
-        unsupported = ["warty", "hoary", "breezy", "edgy", "feisty", "gutsy",
-                       "intrepid", "jaunty"]
+        unsupported = ["warty", "hoary", "breezy", "edgy", "feisty", "gutsy", 
"intrepid", "jaunty"]
         self.assertEqual(self._distro_info.unsupported(self._date), 
unsupported)
 
     def test_current_unsupported(self):
         """Test: List all unsupported Ubuntu distributions today."""
-        unsupported = set(["warty", "hoary", "breezy", "edgy", "feisty",
-                           "gutsy", "intrepid", "jaunty"])
-        self.assertEqual(unsupported -
-                         set(self._distro_info.unsupported()), set())
+        unsupported = {"warty", "hoary", "breezy", "edgy", "feisty", "gutsy", 
"intrepid", "jaunty"}
+        self.assertEqual(unsupported - set(self._distro_info.unsupported()), 
set())
 
     def test_valid(self):
         """Test: Check for valid Ubuntu distribution."""
@@ -160,24 +190,23 @@
     def test_codename(self):
         """Test: Check result set to codename."""
         self.assertEqual(self._distro_info.lts(self._date, "codename"), 
"lucid")
-        self.assertEqual(self._distro_info.devel(self._date, 
result="codename"),
-                         "natty")
+        self.assertEqual(self._distro_info.devel(self._date, 
result="codename"), "natty")
 
     def test_version(self):
         """Test: Check result set to version."""
-        self.assertEqual(self._distro_info.version("lucid"), '10.04 LTS')
-        self.assertEqual(self._distro_info.version("Maverick Meerkat"), 
'10.10')
+        self.assertEqual(self._distro_info.version("lucid"), "10.04 LTS")
+        self.assertEqual(self._distro_info.version("Maverick Meerkat"), 
"10.10")
 
     def test_fullname(self):
         """Test: Check result set to fullname."""
-        self.assertEqual(self._distro_info.stable(self._date, "fullname"),
-                         'Ubuntu 10.10 "Maverick Meerkat"')
-        self.assertEqual(self._distro_info.lts(self._date, result="fullname"),
-                         'Ubuntu 10.04 LTS "Lucid Lynx"')
+        self.assertEqual(
+            self._distro_info.stable(self._date, "fullname"), 'Ubuntu 10.10 
"Maverick Meerkat"'
+        )
+        self.assertEqual(
+            self._distro_info.lts(self._date, result="fullname"), 'Ubuntu 
10.04 LTS "Lucid Lynx"'
+        )
 
     def test_release(self):
         """Test: Check result set to release."""
-        self.assertEqual(self._distro_info.devel(self._date, "release"),
-                         "11.04")
-        self.assertEqual(self._distro_info.lts(self._date, result="release"),
-                         "10.04 LTS")
+        self.assertEqual(self._distro_info.devel(self._date, "release"), 
"11.04")
+        self.assertEqual(self._distro_info.lts(self._date, result="release"), 
"10.04 LTS")
diff -Nru distro-info-0.21/python/distro_info_test/test_flake8.py 
distro-info-1.0~deb10u1/python/distro_info_test/test_flake8.py
--- distro-info-0.21/python/distro_info_test/test_flake8.py     2018-11-11 
17:02:27.000000000 -0400
+++ distro-info-1.0~deb10u1/python/distro_info_test/test_flake8.py      
2021-04-22 11:54:50.000000000 -0400
@@ -31,21 +31,35 @@
 
     def test_flake8(self):
         """Test: Run flake8 on Python source code"""
-        cmd = [sys.executable, "-m", "flake8", "--max-line-length=99"] + 
get_source_files()
+        cmd = [
+            sys.executable,
+            "-m",
+            "flake8",
+            "--ignore",
+            "H301,H403,H405,W504,W503",
+            "--max-line-length=99",
+        ] + get_source_files()
         if unittest_verbosity() >= 2:
             sys.stderr.write("Running following command:\n{}\n".format(" 
".join(cmd)))
-        process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                                   stderr=subprocess.PIPE, close_fds=True)
+        process = subprocess.Popen(
+            cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True
+        )
 
         out, err = process.communicate()
         if process.returncode != 0:  # pragma: no cover
             msgs = []
             if err:
-                msgs.append("flake8 exited with code {} and has unexpected 
output on stderr:\n{}"
-                            .format(process.returncode, err.decode().rstrip()))
+                msgs.append(
+                    "flake8 exited with code {} and has unexpected output on 
stderr:\n{}".format(
+                        process.returncode, err.decode().rstrip()
+                    )
+                )
             if out:
                 msgs.append("flake8 found 
issues:\n{}".format(out.decode().rstrip()))
             if not msgs:
-                msgs.append("flake8 exited with code {} and has no output on 
stdout or stderr."
-                            .format(process.returncode))
+                msgs.append(
+                    "flake8 exited with code {} and has no output on stdout or 
stderr.".format(
+                        process.returncode
+                    )
+                )
             self.fail("\n".join(msgs))
diff -Nru distro-info-0.21/python/distro_info_test/test_help.py 
distro-info-1.0~deb10u1/python/distro_info_test/test_help.py
--- distro-info-0.21/python/distro_info_test/test_help.py       2017-04-30 
15:43:03.000000000 -0400
+++ distro-info-1.0~deb10u1/python/distro_info_test/test_help.py        
2021-04-22 11:54:50.000000000 -0400
@@ -31,23 +31,29 @@
     @classmethod
     def populate(cls):
         for script in setup.SCRIPTS:
-            setattr(cls, 'test_' + script, cls.make_help_tester(script))
+            setattr(cls, "test_" + script, cls.make_help_tester(script))
 
     @classmethod
     def make_help_tester(cls, script):
         def tester(self):
-            null = open('/dev/null', 'r')
-            process = subprocess.Popen(['./' + script, '--help'],
-                                       close_fds=True, stdin=null,
-                                       stdout=subprocess.PIPE,
-                                       stderr=subprocess.PIPE)
+            null = open("/dev/null", "r")
+            process = subprocess.Popen(
+                ["./" + script, "--help"],
+                close_fds=True,
+                stdin=null,
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+            )
             started = time.time()
             out = []
 
             fds = [process.stdout.fileno(), process.stderr.fileno()]
             for file_descriptor in fds:
-                fcntl.fcntl(file_descriptor, fcntl.F_SETFL,
-                            fcntl.fcntl(file_descriptor, fcntl.F_GETFL) | 
os.O_NONBLOCK)
+                fcntl.fcntl(
+                    file_descriptor,
+                    fcntl.F_SETFL,
+                    fcntl.fcntl(file_descriptor, fcntl.F_GETFL) | 
os.O_NONBLOCK,
+                )
 
             while time.time() - started < TIMEOUT:
                 for file_descriptor in select.select(fds, [], fds, TIMEOUT)[0]:
@@ -62,10 +68,13 @@
                     os.kill(process.pid, signal.SIGKILL)
             null.close()
 
-            self.assertEqual(process.poll(), 0,
-                             "%s failed to return usage within %i seconds.\n"
-                             "Output:\n%s"
-                             % (script, TIMEOUT, ''.encode('ascii').join(out)))
+            self.assertEqual(
+                process.poll(),
+                0,
+                "%s failed to return usage within %i seconds.\n"
+                "Output:\n%s" % (script, TIMEOUT, 
"".encode("ascii").join(out)),
+            )
             process.stdout.close()
             process.stderr.close()
+
         return tester
diff -Nru distro-info-0.21/python/distro_info_test/test_pylint.py 
distro-info-1.0~deb10u1/python/distro_info_test/test_pylint.py
--- distro-info-0.21/python/distro_info_test/test_pylint.py     2018-11-11 
17:02:27.000000000 -0400
+++ distro-info-1.0~deb10u1/python/distro_info_test/test_pylint.py      
2021-04-22 11:54:50.000000000 -0400
@@ -40,8 +40,9 @@
         cmd = [sys.executable, "-m", "pylint", "--rcfile=" + CONFIG, "--"] + 
get_source_files()
         if unittest_verbosity() >= 2:
             sys.stderr.write("Running following command:\n{}\n".format(" 
".join(cmd)))
-        process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
stderr=subprocess.PIPE,
-                                   close_fds=True)
+        process = subprocess.Popen(
+            cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True
+        )
         out, err = process.communicate()
 
         if process.returncode != 0:  # pragma: no cover
@@ -50,19 +51,26 @@
             # ------------------------------------
             # Your code has been rated at 10.00/10
             #
-            out = re.sub("^(-+|Your code has been rated at .*)$", "", 
out.decode(),
-                         flags=re.MULTILINE).rstrip()
+            out = re.sub(
+                "^(-+|Your code has been rated at .*)$", "", out.decode(), 
flags=re.MULTILINE
+            ).rstrip()
 
             # Strip logging of used config file (introduced in pylint 1.8)
             err = re.sub("^Using config file .*\n", "", err.decode()).rstrip()
 
             msgs = []
             if err:
-                msgs.append("pylint exited with code {} and has unexpected 
output on stderr:\n{}"
-                            .format(process.returncode, err))
+                msgs.append(
+                    "pylint exited with code {} and has unexpected output on 
stderr:\n{}".format(
+                        process.returncode, err
+                    )
+                )
             if out:
                 msgs.append("pylint found issues:\n{}".format(out))
             if not msgs:
-                msgs.append("pylint exited with code {} and has no output on 
stdout or stderr."
-                            .format(process.returncode))
+                msgs.append(
+                    "pylint exited with code {} and has no output on stdout or 
stderr.".format(
+                        process.returncode
+                    )
+                )
             self.fail("\n".join(msgs))
diff -Nru distro-info-0.21/python/setup.py 
distro-info-1.0~deb10u1/python/setup.py
--- distro-info-0.21/python/setup.py    2018-11-11 17:01:13.000000000 -0400
+++ distro-info-1.0~deb10u1/python/setup.py     2021-04-22 11:54:50.000000000 
-0400
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 import os
 import re
@@ -7,11 +7,8 @@
 
 
 PACKAGES = []
-PY_MODULES = ['distro_info']
-SCRIPTS = [
-    'debian-distro-info',
-    'ubuntu-distro-info',
-]
+PY_MODULES = ["distro_info"]
+SCRIPTS = ["debian-distro-info", "ubuntu-distro-info"]
 
 
 def get_debian_version():
@@ -26,9 +23,9 @@
     return version
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     setup(
-        name='distro-info',
+        name="distro-info",
         version=get_debian_version(),
         py_modules=PY_MODULES,
         packages=PACKAGES,
diff -Nru distro-info-0.21/python/ubuntu-distro-info 
distro-info-1.0~deb10u1/python/ubuntu-distro-info
--- distro-info-0.21/python/ubuntu-distro-info  2018-11-11 17:07:21.000000000 
-0400
+++ distro-info-1.0~deb10u1/python/ubuntu-distro-info   2021-04-22 
11:54:50.000000000 -0400
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 # Copyright (C) 2009-2011, Benjamin Drung <bdr...@debian.org>
 #
@@ -38,10 +38,10 @@
                         help="list all known versions")
     parser.add_argument("-d", "--devel", dest="devel", action="store_true",
                         help="latest development version")
-    parser.add_argument("--lts", dest="lts", action="store_true",
-                        help="latest long term support (LTS) version")
     parser.add_argument("-s", "--stable", dest="stable", action="store_true",
                         help="latest stable version")
+    parser.add_argument("--lts", dest="lts", action="store_true",
+                        help="latest long term support (LTS) version")
     parser.add_argument("--supported", dest="supported", action="store_true",
                         help="list of all supported stable versions")
     parser.add_argument("--unsupported", dest="unsupported", 
action="store_true",
diff -Nru distro-info-0.21/shell/debian-distro-info.in 
distro-info-1.0~deb10u1/shell/debian-distro-info.in
--- distro-info-0.21/shell/debian-distro-info.in        2012-03-27 
06:20:02.000000000 -0400
+++ distro-info-1.0~deb10u1/shell/debian-distro-info.in 2021-04-22 
11:54:50.000000000 -0400
@@ -17,7 +17,7 @@
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 DISTRO_INFO_NAME="Debian"
-DISTRO_INFO_ARGS="--all --devel --oldstable --stable --supported
+DISTRO_INFO_ARGS="--all --devel --elts --lts --oldstable --stable --supported
                   --testing --unsupported"
 DISTRO_INFO_DATA="/usr/share/distro-info/debian.csv"
 
@@ -32,10 +32,12 @@
       --date=DATE    date for calculating the version (default: today)
   -a  --all          list all known versions
   -d  --devel        latest development version
-  -o  --oldstable    latest oldstable version
+  -t  --testing      current testing version
   -s  --stable       latest stable version
+  -o  --oldstable    latest oldstable version
       --supported    list of all supported stable versions
-  -t  --testing      current testing version
+  -l  --lts          list of all LTS versions
+  -e  --elts         list of all Extended LTS versions
       --unsupported  list of all unsupported stable versions
   -c  --codename     print the codename (default)
   -r  --release      print the release version
@@ -59,6 +61,15 @@
                store
        return 1;
 }
+cb_supported() {
+       date_ge "$eol" "$CMP_DATE" && created
+}
+cb_lts() {
+       date_ge "$eollts" "$CMP_DATE" && ! date_ge "$eol" "$CMP_DATE" && created
+}
+cb_elts() {
+       date_ge "$eolelts" "$CMP_DATE" && ! date_ge "$eollts" "$CMP_DATE" && 
created
+}
 
 main "$@"
 
diff -Nru distro-info-0.21/shell/distro-info-util.sh 
distro-info-1.0~deb10u1/shell/distro-info-util.sh
--- distro-info-0.21/shell/distro-info-util.sh  2012-05-28 19:24:55.000000000 
-0400
+++ distro-info-1.0~deb10u1/shell/distro-info-util.sh   2021-04-22 
11:54:50.000000000 -0400
@@ -25,7 +25,14 @@
        s_created=$created;
        s_release=$release;
        s_eol=$eol;
+#BEGIN debian#
+       s_eollts=$eollts;
+       s_eolelts=$eolelts;
+#END debian#
+#BEGIN ubuntu#
        s_eols=$eols;
+       s_eolesm=$eolesm;
+#END ubuntu#
 }
 restore() {
        # restore data previously stored with store
@@ -35,7 +42,14 @@
        created=$s_created;
        release=$s_release;
        eol=$s_eol;
+#BEGIN debian#
+       eollts=$s_eollts;
+       eolelts=$s_eolelts;
+#END debian#
+#BEGIN ubuntu#
        eols=$s_eols;
+       eolesm=$s_eolesm;
+#END ubuntu#
 }
 
 created() {
@@ -60,7 +74,13 @@
 next_is() {
        # call a function as if you were calling it for next
        local version=$n_version codename=$n_codename series=$n_series
-       local created=$n_created release=$n_release eol=$n_eol eols=$n_eols
+       local created=$n_created release=$n_release eol=$n_eol
+#BEGIN debian#
+       local eollts=$n_eollts eolelts=$in_eolelts
+#END debian#
+#BEGIN ubuntu#
+       local eols=$n_eols eolesm=$n_eolesm
+#END ubuntu#
        "$@"
 }
 
@@ -75,9 +95,6 @@
        released && [ -n "$n_version" ] && ! next_is released && store
        return 1;
 }
-cb_supported() {
-       date_ge "$eols" "$CMP_DATE" && created
-}
 cb_unsupported() {
        created && ! cb_supported
 }
@@ -97,20 +114,40 @@
        local callback="$1" fmt="$2" found=0
        shift 2;
        IFS=","
-       local version codename series created release eol eols
-       local n_version n_codename n_series n_created n_release n_eol n_eols
+       local version codename series created release eol
+       local n_version n_codename n_series n_created n_release n_eol
+#BEGIN debian#
+       local eollts n_eollts eolelts n_eolelts
+#END debian#
+#BEGIN ubuntu#
+       local eols n_eols eolesm n_eolesm
+#END ubuntu#
        {
        read tmpvar # header of file
        read version codename series created release eol eols
        [ -n "$eol" ] || eol="9999-99-99"
        [ -n "$eols" ] || eols=$eol
-       while read n_version n_codename n_series n_created n_release n_eol 
n_eols; do
+       while read n_version n_codename n_series n_created n_release n_eol \
+#BEGIN debian#
+               n_eollts n_eolelts
+#END debian#
+#BEGIN ubuntu#
+               n_eols n_eolesm
+#END ubuntu#
+       do
                [ -n "$n_eol" ] || n_eol="9999-99-99"
+#BEGIN ubuntu#
                [ -n "$n_eols" ] || n_eols=$n_eol
+#END ubuntu#
                "$callback" && found=$(($found+1)) && "$fmt"
                version=$n_version; codename=$n_codename; series=$n_series
                created=$n_created; release=$n_release;   eol=$n_eol;
-               eols=$n_eols
+#BEGIN debian#
+               eollts=$n_eollts; eolelts=$n_eolelts;
+#END debian#
+#BEGIN ubuntu#
+               eols=$n_eols; eolesm=$n_eolesm;
+#END ubuntu#
        done
        } < "$DISTRO_INFO_DATA"
 
@@ -160,11 +197,11 @@
                        -a|--all)
                                [ -z "$callback" ] || { not_exactly_one; return 
1; }
                                callback="all";;
-                       --date=*)
+                       --date=*)
                                date=${1#*=};
                                [ -n "$date" ] || { date_requires_arg; return 
1; }
                                ;;
-                       --date)
+                       --date)
                                date="$2";
                                [ -n "$2" ] || { date_requires_arg; return 1; }
                                shift;;
@@ -181,11 +218,20 @@
                        -r|--release)  fmt="print_release";;
                        -f|--fullname) fmt="print_fullname";;
 #BEGIN ubuntu#
-                       --lts)
+                       --lts)
                                [ -z "$callback" ] || { not_exactly_one; return 
1; }
                                callback="lts";;
+                       --supported-esm)
+                               [ -z "$callback" ] || { not_exactly_one; return 
1; }
+                               callback="supported_esm";;
 #END ubuntu#
 #BEGIN debian#
+                       -e|--elts)
+                               [ -z "$callback" ] || { not_exactly_one; return 
1; }
+                               callback="elts";;
+                       -l|--lts)
+                               [ -z "$callback" ] || { not_exactly_one; return 
1; }
+                               callback="lts";;
                        -o|--oldstable|--old)
                                [ -z "$callback" ] || { not_exactly_one; return 
1; }
                                callback="oldstable";;
diff -Nru distro-info-0.21/shell/Makefile distro-info-1.0~deb10u1/shell/Makefile
--- distro-info-0.21/shell/Makefile     2012-04-02 09:47:45.000000000 -0400
+++ distro-info-1.0~deb10u1/shell/Makefile      2021-04-22 11:54:50.000000000 
-0400
@@ -3,10 +3,10 @@
 
 build: debian-distro-info ubuntu-distro-info
 
-%-distro-info: debian-distro-info.in distro-info-util.sh
+%-distro-info: %-distro-info.in distro-info-util.sh
        sed -e '/^\. .*distro-info-util.sh\"$$/r distro-info-util.sh' $< | \
                sed -e '/^##/d;/^\. .*distro-info-util.sh\"$$/d' | \
-               python -c 'import re,sys;print re.sub("(?<=\n)#BEGIN 
\w*#\n(.|\n)*?\n#END \w*#\n", "", re.sub("(?<=\n)#(BEGIN|END) $*#\n", "", 
sys.stdin.read())),' > $@
+               python3 -c 'import re,sys;print(re.sub("(?<=\n)#BEGIN 
\w*#\n(.|\n)*?\n#END \w*#\n", "", re.sub("(?<=\n)#(BEGIN|END) $*#\n", "", 
sys.stdin.read())), end="")' > $@
        chmod +x $@
 
 install: debian-distro-info ubuntu-distro-info
diff -Nru distro-info-0.21/shell/ubuntu-distro-info.in 
distro-info-1.0~deb10u1/shell/ubuntu-distro-info.in
--- distro-info-0.21/shell/ubuntu-distro-info.in        2012-03-27 
06:20:06.000000000 -0400
+++ distro-info-1.0~deb10u1/shell/ubuntu-distro-info.in 2021-04-22 
11:54:50.000000000 -0400
@@ -17,27 +17,29 @@
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 DISTRO_INFO_NAME="Ubuntu"
-DISTRO_INFO_ARGS="--all --devel --lts --stable --supported --unsupported"
+DISTRO_INFO_ARGS="--all --devel --lts --stable --supported --supported-esm
+                  --unsupported"
 DISTRO_INFO_DATA="/usr/share/distro-info/ubuntu.csv"
 
 . "${0%/*}/distro-info-util.sh"
 
 Usage() {
        cat <<EOF
-Usage: ${0##*/} [options]
+Usage: ubuntu-distro-info [options]
 
 Options:
-  -h  --help         show this help message and exit
-      --date=DATE    date for calculating the version (default: today)
-  -a  --all          list all known versions
-  -d  --devel        latest development version
-      --lts          latest long term support (LTS) version
-  -s  --stable       latest stable version
-      --supported    list of all supported stable versions
-      --unsupported  list of all unsupported stable versions
-  -c  --codename     print the codename (default)
-  -r  --release      print the release version
-  -f  --fullname     print the full name
+  -h  --help          show this help message and exit
+      --date=DATE     date for calculating the version (default: today)
+  -a  --all           list all known versions
+  -d  --devel         latest development version
+  -s  --stable        latest stable version
+      --lts           latest long term support (LTS) version
+      --supported     list of all supported stable versions
+      --supported-esm list of all supported stable versions
+      --unsupported   list of all unsupported stable versions
+  -c  --codename      print the codename (default)
+  -r  --release       print the release version
+  -f  --fullname      print the full name
 
 See ubuntu-distro-info(1) for more info.
 EOF
@@ -47,6 +49,12 @@
        devel && store
        return 1
 }
+cb_supported() {
+       date_ge "$eols" "$CMP_DATE" && created
+}
+cb_supported_esm() {
+       date_ge "$eolesm" "$CMP_DATE" && created
+}
 cb_lts() {
        [ "${version#*LTS}" != "${version}" ] && released && store
        return 1;
diff -Nru distro-info-0.21/test-debian-distro-info 
distro-info-1.0~deb10u1/test-debian-distro-info
--- distro-info-0.21/test-debian-distro-info    2018-10-11 20:11:26.000000000 
-0400
+++ distro-info-1.0~deb10u1/test-debian-distro-info     2021-04-22 
11:54:50.000000000 -0400
@@ -69,6 +69,14 @@
     success "--date=2011-01-10 --supported" "$result"
 }
 
+testLTS() {
+    success "--date=2016-02-28 --lts" "squeeze"
+}
+
+testELTS() {
+    success "--date=2018-09-01 --elts" "wheezy"
+}
+
 testUnsupported() {
     local result="buzz
 rex
@@ -160,15 +168,17 @@
       --date=DATE        date for calculating the version (default: today)
       --series=SERIES    series to calculate the version for
   -y[MILESTONE]          additionally, display days until milestone
-      --days=[MILESTONE] (created, release, eol)
+      --days=[MILESTONE] (created, release, eol, eol-lts, eol-elts)
       --alias=DIST       print the alias (oldstable, stable, testing, unstable)
                          relative to the given distribution codename
   -a  --all              list all known versions
   -d  --devel            latest development version
-  -o  --oldstable        latest oldstable version
+  -t  --testing          current testing version
   -s  --stable           latest stable version
+  -o  --oldstable        latest oldstable version
       --supported        list of all supported stable versions
-  -t  --testing          current testing version
+  -l  --lts              list of all LTS supported versions
+  -e  --elts             list of all Extended LTS supported versions
       --unsupported      list of all unsupported stable versions
   -c  --codename         print the codename (default)
   -f  --fullname         print the full name
@@ -180,7 +190,7 @@
 }
 
 testExactlyOne() {
-    local result='debian-distro-info: You have to select exactly one of 
--alias, --all, --devel, --oldstable, --stable, --supported, --series, 
--testing, --unsupported.'
+    local result='debian-distro-info: You have to select exactly one of 
--alias, --all, --devel, --elts, --lts, --oldstable, --stable, --supported, 
--series, --testing, --unsupported.'
     failure "" "$result"
     failure "-ad" "$result"
     failure "--alias foo -a" "$result"
@@ -189,7 +199,7 @@
 testUnrecognizedOption() {
     failure "--foo" "debian-distro-info: unrecognized option \`--foo'"
     failure "-x" "debian-distro-info: unrecognized option \`-x'"
-    failure "--lts" "debian-distro-info: unrecognized option \`--lts'"
+    failure "--supported-esm" "debian-distro-info: unrecognized option 
\`--supported-esm'"
 }
 
 testUnrecognizedArguments() {
@@ -315,6 +325,41 @@
     success "--testing --date=$date --days=eol -c" "etch 1045"
     success "--testing --date=$date --days=eol -f" "Debian 4.0 \"Etch\" 1045"
     success "--testing --date=$date --days=eol -r" "4.0 1045"
+
+    # day before wheezy was released
+    date=2013-05-03
+
+    success "--testing --date=$date" "wheezy"
+
+    success "--testing --date=$date --days=created" "-817"
+    success "--testing --date=$date --days=created -c" "wheezy -817"
+    success "--testing --date=$date --days=created -f" "Debian 7 \"Wheezy\" 
-817"
+    success "--testing --date=$date --days=created -r" "7 -817"
+
+    success "--testing --date=$date --days" "1"
+    success "--testing --date=$date --days -c" "wheezy 1"
+    success "--testing --date=$date --days -f" "Debian 7 \"Wheezy\" 1"
+    success "--testing --date=$date --days -r" "7 1"
+
+    success "--testing --date=$date --days=release" "1"
+    success "--testing --date=$date --days=release -c" "wheezy 1"
+    success "--testing --date=$date --days=release -f" "Debian 7 \"Wheezy\" 1"
+    success "--testing --date=$date --days=release -r" "7 1"
+
+    success "--testing --date=$date --days=eol" "1089"
+    success "--testing --date=$date --days=eol -c" "wheezy 1089"
+    success "--testing --date=$date --days=eol -f" "Debian 7 \"Wheezy\" 1089"
+    success "--testing --date=$date --days=eol -r" "7 1089"
+
+    success "--testing --date=$date --days=eol-lts" "1854"
+    success "--testing --date=$date --days=eol-lts -c" "wheezy 1854"
+    success "--testing --date=$date --days=eol-lts -f" "Debian 7 \"Wheezy\" 
1854"
+    success "--testing --date=$date --days=eol-lts -r" "7 1854"
+
+    success "--testing --date=$date --days=eol-elts" "2615"
+    success "--testing --date=$date --days=eol-elts -c" "wheezy 2615"
+    success "--testing --date=$date --days=eol-elts -f" "Debian 7 \"Wheezy\" 
2615"
+    success "--testing --date=$date --days=eol-elts -r" "7 2615"
 }
 
 . shunit2
diff -Nru distro-info-0.21/test-ubuntu-distro-info 
distro-info-1.0~deb10u1/test-ubuntu-distro-info
--- distro-info-0.21/test-ubuntu-distro-info    2018-10-11 20:11:26.000000000 
-0400
+++ distro-info-1.0~deb10u1/test-ubuntu-distro-info     2021-04-22 
11:54:50.000000000 -0400
@@ -117,9 +117,9 @@
     success "--date=2011-01-10 --fullname --lts --days=eol" \
         'Ubuntu 10.04 LTS "Lucid Lynx" 850'
     success "--date=2011-01-10 --fullname --lts -yeol-server" \
-        'Ubuntu 10.04 LTS "Lucid Lynx" 1570'
+        'Ubuntu 10.04 LTS "Lucid Lynx" 1571'
     success "--date=2011-01-10 --fullname --lts --days=eol-server" \
-        'Ubuntu 10.04 LTS "Lucid Lynx" 1570'
+        'Ubuntu 10.04 LTS "Lucid Lynx" 1571'
 }
 
 testRelease() {
@@ -141,9 +141,9 @@
     success "--date=2011-01-10 --lts --release -yeol" \
         "10.04 LTS 850"
     success "--date=2011-01-10 --lts --release --days=eol-server" \
-        "10.04 LTS 1570"
+        "10.04 LTS 1571"
     success "--date=2011-01-10 --lts --release -yeol-server" \
-        "10.04 LTS 1570"
+        "10.04 LTS 1571"
 
     success "--date=2011-01-10 -r --stable" "10.10"
 }
@@ -171,12 +171,13 @@
       --date=DATE        date for calculating the version (default: today)
       --series=SERIES    series to calculate the version for
   -y[MILESTONE]          additionally, display days until milestone
-      --days=[MILESTONE] (created, release, eol, eol-server)
+      --days=[MILESTONE] (created, release, eol, eol-server, eol-esm)
   -a  --all              list all known versions
   -d  --devel            latest development version
-      --lts              latest long term support (LTS) version
   -s  --stable           latest stable version
+      --lts              latest long term support (LTS) version
       --supported        list of all supported stable versions
+      --supported-esm    list of all Ubuntu Advantage supported stable versions
       --unsupported      list of all unsupported stable versions
   -c  --codename         print the codename (default)
   -f  --fullname         print the full name
@@ -188,7 +189,7 @@
 }
 
 testExactlyOne() {
-    local result='ubuntu-distro-info: You have to select exactly one of --all, 
--devel, --latest, --lts, --stable, --supported, --series, --unsupported.'
+    local result='ubuntu-distro-info: You have to select exactly one of --all, 
--devel, --latest, --lts, --stable, --supported, --supported-esm, --series, 
--unsupported.'
     failure "" "$result"
     failure "--date=2009-01-10 -sad" "$result"
 }
@@ -271,10 +272,10 @@
     success "--date=$date --lts --days=eol -f" "Ubuntu 10.04 LTS \"Lucid 
Lynx\" 1105"
     success "--date=$date --lts --days=eol -r" "10.04 LTS 1105"
 
-    success "--date=$date --lts --days=eol-server" "1825"
-    success "--date=$date --lts --days=eol-server -c" "lucid 1825"
-    success "--date=$date --lts --days=eol-server -f" "Ubuntu 10.04 LTS 
\"Lucid Lynx\" 1825"
-    success "--date=$date --lts --days=eol-server -r" "10.04 LTS 1825"
+    success "--date=$date --lts --days=eol-server" "1826"
+    success "--date=$date --lts --days=eol-server -c" "lucid 1826"
+    success "--date=$date --lts --days=eol-server -f" "Ubuntu 10.04 LTS 
\"Lucid Lynx\" 1826"
+    success "--date=$date --lts --days=eol-server -r" "10.04 LTS 1826"
 
     # date precise released
     date=2012-04-26
@@ -296,15 +297,15 @@
     success "--date=$date --lts --days -f" "Ubuntu 12.04 LTS \"Precise 
Pangolin\" 0"
     success "--date=$date --lts --days -r" "12.04 LTS 0"
 
-    success "--date=$date --lts --days=eol" "1826"
-    success "--date=$date --lts --days=eol -c" "precise 1826"
-    success "--date=$date --lts --days=eol -f" "Ubuntu 12.04 LTS \"Precise 
Pangolin\" 1826"
-    success "--date=$date --lts --days=eol -r" "12.04 LTS 1826"
-
-    success "--date=$date --lts --days=eol-server" "(unknown)"
-    success "--date=$date --lts --days=eol-server -c" "precise (unknown)"
-    success "--date=$date --lts --days=eol-server -f" "Ubuntu 12.04 LTS 
\"Precise Pangolin\" (unknown)"
-    success "--date=$date --lts --days=eol-server -r" "12.04 LTS (unknown)"
+    success "--date=$date --lts --days=eol" "1828"
+    success "--date=$date --lts --days=eol -c" "precise 1828"
+    success "--date=$date --lts --days=eol -f" "Ubuntu 12.04 LTS \"Precise 
Pangolin\" 1828"
+    success "--date=$date --lts --days=eol -r" "12.04 LTS 1828"
+
+    success "--date=$date --lts --days=eol-server" "1828"
+    success "--date=$date --lts --days=eol-server -c" "precise 1828"
+    success "--date=$date --lts --days=eol-server -f" "Ubuntu 12.04 LTS 
\"Precise Pangolin\" 1828"
+    success "--date=$date --lts --days=eol-server -r" "12.04 LTS 1828"
 
     # day before raring was released
     date=2013-04-24
diff -Nru distro-info-0.21/ubuntu-distro-info.c 
distro-info-1.0~deb10u1/ubuntu-distro-info.c
--- distro-info-0.21/ubuntu-distro-info.c       2014-05-10 13:00:26.000000000 
-0400
+++ distro-info-1.0~deb10u1/ubuntu-distro-info.c        2021-04-22 
11:54:50.000000000 -0400
@@ -16,7 +16,7 @@
 
 #define UBUNTU
 #define CSV_NAME "ubuntu"
-#define CSV_HEADER "version,codename,series,created,release,eol,eol-server"
+#define CSV_HEADER 
"version,codename,series,created,release,eol,eol-server,eol-esm"
 #define DISTRO_NAME "Ubuntu"
 #define NAME "ubuntu-distro-info"
 
diff -Nru distro-info-data-0.41+deb10u3/debian/changelog 
distro-info-data-0.47~deb10u1/debian/changelog
--- distro-info-data-0.41+deb10u3/debian/changelog      2020-11-02 
16:44:14.000000000 -0400
+++ distro-info-data-0.47~deb10u1/debian/changelog      2021-04-22 
11:46:22.000000000 -0400
@@ -1,3 +1,80 @@
+distro-info-data (0.47~deb10u1) buster; urgency=medium
+
+  * Backport 0.47 to buster. Highlights:
+    - Add "eol-esm" for Ubuntu Extended Security Maintenance support.
+    - Add "eol-lts" for Debian LTS (Closes: #782685)
+    - Add "eol-elts" for Debian ELTS.
+    - Add estimated dates for Buster EOL and Buster LTS EOL.
+    - Add Debian 13 "Trixie", with a rough date.
+    - Correct the EOL date for Debian Jessie.
+    - Tweak eol and eol-esm dates, by a couple of days, for Ubuntu 6.10, 9.10,
+      10.04, 12.04, 15.04, 15.10, 19.04 to match announced EOL dates.
+    - Add Ubuntu 21.04, Impish Indri.
+
+ -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 11:46:22 -0400
+
+distro-info-data (0.47) unstable; urgency=medium
+
+  * Add Ubuntu 21.04, Impish Indri.
+
+ -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 10:30:18 -0400
+
+distro-info-data (0.46) unstable; urgency=medium
+
+  * Add "eol-server" dates matching "eol", for LTS releases, as there hasn't
+    been a distinction between the two, for a while.
+    (Closes: #922090, LP: #1814976).
+  * Add "eol-esm" column: EOL for Ubuntu Extended Security Maintenance support.
+    (LP: #1808038)
+  * Drop ancient Replaces: distro-info (<< 0.3~). No longer needed.
+  * Add "eol-lts" for Debian LTS (Closes: #782685)
+  * Add estimated dates for Buster EOL and Buster LTS EOL.
+  * Publish the data to GitLab pages. (Closes: #973904)
+  * Bump Standards-Version to 4.5.1, no changes needed.
+  * Bump copyright years.
+  * Correct the EOL date for Debian Jessie.
+  * Add Debian 13 "Trixie", with a rough date.
+  * Add "up-to-date" testing tool.
+  * Add an autopkgtest, running the validation and up-to-date tests.
+  * "black" Python.
+  * Add "eol-elts" for Debian ELTS.
+  * Tweak eol and eol-esm dates, by a couple of days, for Ubuntu 6.10, 9.10,
+    10.04, 12.04, 15.04, 15.10, 19.04 to match announced EOL dates.
+
+ -- Stefano Rivera <stefa...@debian.org>  Fri, 29 Jan 2021 13:41:20 -0700
+
+distro-info-data (0.45) unstable; urgency=medium
+
+  * Add Ubuntu 21.04, Hirsute Hippo.
+
+ -- Stefano Rivera <stefa...@debian.org>  Thu, 29 Oct 2020 13:21:12 -0700
+
+distro-info-data (0.44) unstable; urgency=medium
+
+  * Add Ubuntu 20.10, Groovy Gorilla.
+  * Add a guessed EOL date for Debian Stretch.
+  * Bump Standards-Version to 4.5.0, no changes needed.
+
+ -- Stefano Rivera <stefa...@debian.org>  Fri, 24 Apr 2020 08:29:10 -0700
+
+distro-info-data (0.43) unstable; urgency=medium
+
+  * Add Ubuntu 20.04 LTS, Focal Fossa.
+  * Bump Standards-Version to 4.4.1, no changes needed.
+
+ -- Stefano Rivera <stefa...@debian.org>  Thu, 17 Oct 2019 13:10:30 -0700
+
+distro-info-data (0.42) unstable; urgency=medium
+
+  * validate-csv-data:
+    - Switch to Python 3
+    - Switch from optparse to argparse
+    - Fix pylint issues
+  * Bump Standards-Version to 4.4.0
+  * Switch to debhelper 12
+
+ -- Benjamin Drung <bdr...@debian.org>  Tue, 23 Jul 2019 12:29:47 +0200
+
 distro-info-data (0.41+deb10u3) buster; urgency=medium
 
   * Update data to 0.45:
diff -Nru distro-info-data-0.41+deb10u3/debian/compat 
distro-info-data-0.47~deb10u1/debian/compat
--- distro-info-data-0.41+deb10u3/debian/compat 2020-11-02 16:44:14.000000000 
-0400
+++ distro-info-data-0.47~deb10u1/debian/compat 1969-12-31 20:00:00.000000000 
-0400
@@ -1 +0,0 @@
-9
diff -Nru distro-info-data-0.41+deb10u3/debian/control 
distro-info-data-0.47~deb10u1/debian/control
--- distro-info-data-0.41+deb10u3/debian/control        2020-11-02 
16:44:14.000000000 -0400
+++ distro-info-data-0.47~deb10u1/debian/control        2021-04-22 
11:46:22.000000000 -0400
@@ -3,8 +3,8 @@
 Priority: optional
 Maintainer: Benjamin Drung <bdr...@debian.org>
 Uploaders: Stefano Rivera <stefa...@debian.org>
-Build-Depends: debhelper (>= 9), python
-Standards-Version: 4.3.0
+Build-Depends: debhelper-compat (= 12), python3
+Standards-Version: 4.5.1
 Vcs-Git: https://salsa.debian.org/debian/distro-info-data.git
 Vcs-Browser: https://salsa.debian.org/debian/distro-info-data
 Rules-Requires-Root: no
@@ -13,8 +13,7 @@
 Architecture: all
 Multi-Arch: foreign
 Depends: ${misc:Depends}
-Breaks: distro-info (<< 0.3~)
-Replaces: distro-info (<< 0.3~)
+Breaks: distro-info (<< 1.0~)
 Description: information about the distributions' releases (data files)
  Information about all releases of Debian and Ubuntu. The distro-info script
  will give you the codename for e.g. the latest stable release of your
diff -Nru distro-info-data-0.41+deb10u3/debian/copyright 
distro-info-data-0.47~deb10u1/debian/copyright
--- distro-info-data-0.41+deb10u3/debian/copyright      2020-11-02 
16:44:14.000000000 -0400
+++ distro-info-data-0.47~deb10u1/debian/copyright      2021-04-22 
11:46:22.000000000 -0400
@@ -4,7 +4,7 @@
 
 Files: *
 Copyright: 2009-2018, Benjamin Drung <bdr...@debian.org>
-           2009-2018, Stefano Rivera <stefa...@debian.org>
+           2009-2021, Stefano Rivera <stefa...@debian.org>
 License: ISC
  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
diff -Nru distro-info-data-0.41+deb10u3/debian/README.Debian 
distro-info-data-0.47~deb10u1/debian/README.Debian
--- distro-info-data-0.41+deb10u3/debian/README.Debian  2020-11-02 
16:44:14.000000000 -0400
+++ distro-info-data-0.47~deb10u1/debian/README.Debian  2021-04-22 
11:46:22.000000000 -0400
@@ -23,3 +23,8 @@
 
 If there isn't an update available yet, you should be able to install the
 latest version from Debian/unstable.
+
+Or pull it from the Internet at:
+
+* https://debian.pages.debian.net/distro-info-data/debian.csv
+* https://debian.pages.debian.net/distro-info-data/ubuntu.csv
diff -Nru distro-info-data-0.41+deb10u3/debian/tests/control 
distro-info-data-0.47~deb10u1/debian/tests/control
--- distro-info-data-0.41+deb10u3/debian/tests/control  1969-12-31 
20:00:00.000000000 -0400
+++ distro-info-data-0.47~deb10u1/debian/tests/control  2021-04-22 
11:46:22.000000000 -0400
@@ -0,0 +1,2 @@
+Depends: @builddeps@
+Test-Command: make up-to-date
diff -Nru distro-info-data-0.41+deb10u3/debian.csv 
distro-info-data-0.47~deb10u1/debian.csv
--- distro-info-data-0.41+deb10u3/debian.csv    2020-11-02 16:44:14.000000000 
-0400
+++ distro-info-data-0.47~deb10u1/debian.csv    2021-04-22 11:46:22.000000000 
-0400
@@ -1,4 +1,4 @@
-version,codename,series,created,release,eol
+version,codename,series,created,release,eol,eol-lts,eol-elts
 1.1,Buzz,buzz,1993-08-16,1996-06-17,1997-06-05
 1.2,Rex,rex,1996-06-17,1996-12-12,1998-06-05
 1.3,Bo,bo,1996-12-12,1997-06-05,1999-03-09
@@ -9,12 +9,13 @@
 3.1,Sarge,sarge,2002-07-19,2005-06-06,2008-03-30
 4.0,Etch,etch,2005-06-06,2007-04-08,2010-02-15
 5.0,Lenny,lenny,2007-04-08,2009-02-14,2012-02-06
-6.0,Squeeze,squeeze,2009-02-14,2011-02-06,2014-05-31
-7,Wheezy,wheezy,2011-02-06,2013-05-04,2016-04-26
-8,Jessie,jessie,2013-05-04,2015-04-25,2018-06-06
-9,Stretch,stretch,2015-04-25,2017-06-17,2020-07-06
-10,Buster,buster,2017-06-17,2019-07-06
+6.0,Squeeze,squeeze,2009-02-14,2011-02-06,2014-05-31,2016-02-29
+7,Wheezy,wheezy,2011-02-06,2013-05-04,2016-04-26,2018-05-31,2020-06-30
+8,Jessie,jessie,2013-05-04,2015-04-25,2018-06-17,2020-06-30,2022-06-30
+9,Stretch,stretch,2015-04-25,2017-06-17,2020-07-06,2022-06-30
+10,Buster,buster,2017-06-17,2019-07-06,2022-07-06,2024-06-30
 11,Bullseye,bullseye,2019-07-06
 12,Bookworm,bookworm,2021-08-01
+13,Trixie,trixie,2023-08-01
 ,Sid,sid,1993-08-16
 ,Experimental,experimental,1993-08-16
diff -Nru distro-info-data-0.41+deb10u3/.gitlab-ci.yml 
distro-info-data-0.47~deb10u1/.gitlab-ci.yml
--- distro-info-data-0.41+deb10u3/.gitlab-ci.yml        1969-12-31 
20:00:00.000000000 -0400
+++ distro-info-data-0.47~deb10u1/.gitlab-ci.yml        2021-04-22 
11:46:22.000000000 -0400
@@ -0,0 +1,10 @@
+---
+image: debian:stable
+
+pages:
+  script:
+    - mkdir public
+    - cp ubuntu.csv debian.csv public/
+  artifacts:
+    paths:
+      - public
diff -Nru distro-info-data-0.41+deb10u3/lib/tools.py 
distro-info-data-0.47~deb10u1/lib/tools.py
--- distro-info-data-0.41+deb10u3/lib/tools.py  1969-12-31 20:00:00.000000000 
-0400
+++ distro-info-data-0.47~deb10u1/lib/tools.py  2021-04-22 11:46:22.000000000 
-0400
@@ -0,0 +1,70 @@
+# Copyright (C) 2012, Benjamin Drung <bdr...@debian.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""Common parsing and utility functions"""
+
+import argparse
+import datetime
+import os
+import sys
+
+
+def convert_date(string):
+    """Convert a date string in ISO 8601 into a datetime object."""
+    if not string:
+        date = None
+    else:
+        parts = [int(x) for x in string.split("-")]
+        if len(parts) == 3:
+            (year, month, day) = parts
+            date = datetime.date(year, month, day)
+        else:
+            raise ValueError("Date not in ISO 8601 format.")
+    return date
+
+
+def main(validation_function):
+    """Main function with command line parameter parsing."""
+    script_name = os.path.basename(sys.argv[0])
+    usage = "%s [-h] -d|-u csv-file" % (script_name)
+    parser = argparse.ArgumentParser(usage=usage)
+
+    parser.add_argument(
+        "-d",
+        "--debian",
+        dest="debian",
+        action="store_true",
+        default=False,
+        help="validate a Debian CSV file",
+    )
+    parser.add_argument(
+        "-u",
+        "--ubuntu",
+        dest="ubuntu",
+        action="store_true",
+        default=False,
+        help="validate an Ubuntu CSV file",
+    )
+    parser.add_argument("csv_file", metavar="csv-file", help="CSV file to 
validate")
+
+    args = parser.parse_args()
+    if len([x for x in [args.debian, args.ubuntu] if x]) != 1:
+        parser.error("You have to select exactly one of --debian, --ubuntu.")
+
+    if args.debian:
+        distro = "debian"
+    else:
+        distro = "ubuntu"
+
+    return int(not validation_function(args.csv_file, distro))
diff -Nru distro-info-data-0.41+deb10u3/Makefile 
distro-info-data-0.47~deb10u1/Makefile
--- distro-info-data-0.41+deb10u3/Makefile      2020-11-02 16:44:14.000000000 
-0400
+++ distro-info-data-0.47~deb10u1/Makefile      2021-04-22 11:46:22.000000000 
-0400
@@ -1,4 +1,5 @@
 PREFIX ?= /usr
+PYTHON_SOURCES=lib up-to-date validate-csv-data
 
 build:
 
@@ -10,4 +11,14 @@
        ./validate-csv-data -d debian.csv
        ./validate-csv-data -u ubuntu.csv
 
-.PHONY: build install test
+up-to-date:
+       ./up-to-date -d debian.csv
+       ./up-to-date -u ubuntu.csv
+
+black:
+       black $(PYTHON_SOURCES)
+
+pylint:
+       pylint $(PYTHON_SOURCES)
+
+.PHONY: black build install pylint test up-to-date
diff -Nru distro-info-data-0.41+deb10u3/README.md 
distro-info-data-0.47~deb10u1/README.md
--- distro-info-data-0.41+deb10u3/README.md     1969-12-31 20:00:00.000000000 
-0400
+++ distro-info-data-0.47~deb10u1/README.md     2021-04-22 11:46:22.000000000 
-0400
@@ -0,0 +1,54 @@
+# distro-info-data
+
+The `distro-info` package provides centralized lists of code-names and
+release history for the supported distributions (Currently: Debian and
+Ubuntu).
+
+The `distro-info` data (in the `distro-info-data` package) can be
+updated once, and all the packages using it will have the latest
+data. This avoids having to hard-code current development release names
+(and other such volatile data) into packages.
+
+## Outdated Data Errors
+
+If you get an error that the package data is out of date, look for a newer
+distro-info-data package in your distribution's updates.
+
+On Debian, this is:
+deb http://ftp.debian.org/debian stable-updates main
+
+On Ubuntu, it is:
+deb http://archive.ubuntu.com/ubuntu $RELEASE-updates main
+where $RELEASE is the name of your release.
+
+If there isn't an update available yet, you should be able to install the
+latest version from Debian/unstable.
+
+## Online data
+
+Please don't scrape the git interface directly.
+
+This data is available publicly at:
+
+* https://debian.pages.debian.net/distro-info-data/debian.csv
+* https://debian.pages.debian.net/distro-info-data/ubuntu.csv
+
+## Data format
+
+The data is in CSV format. They are parsed by code specific to the
+distribution, so columns use and meaning vary.
+Each row is a release in the distribution's history.
+
+* `version`: Numeric (decimal) release version. Suffixed `LTS` for
+  Ubuntu LTS releases.
+* `codename`: Full human-readable name of the release.
+* `series`: The machine-readable series name (suite).
+* `created`: Date that the release started development. Normally the
+  release date for the previous release.
+* `release`: Official (stable) release date. Not defined when unknown
+   and for suites that will never release (e.g. Debian unstable &
+   experimental).
+* `eol`: The primary End of Life date for the release. Excluding Debian
+   LTS and Ubuntu ESM.
+* `eol-server`: End of Life for use on servers. (Specific to early
+   Ubuntu LTSs).
diff -Nru distro-info-data-0.41+deb10u3/ubuntu.csv 
distro-info-data-0.47~deb10u1/ubuntu.csv
--- distro-info-data-0.41+deb10u3/ubuntu.csv    2020-11-02 16:44:14.000000000 
-0400
+++ distro-info-data-0.47~deb10u1/ubuntu.csv    2021-04-22 11:46:22.000000000 
-0400
@@ -1,35 +1,36 @@
-version,codename,series,created,release,eol,eol-server
+version,codename,series,created,release,eol,eol-server,eol-esm
 4.10,Warty Warthog,warty,2004-03-05,2004-10-20,2006-04-30
 5.04,Hoary Hedgehog,hoary,2004-10-20,2005-04-08,2006-10-31
 5.10,Breezy Badger,breezy,2005-04-08,2005-10-12,2007-04-13
 6.06 LTS,Dapper Drake,dapper,2005-10-12,2006-06-01,2009-07-14,2011-06-01
-6.10,Edgy Eft,edgy,2006-06-01,2006-10-26,2008-04-25
+6.10,Edgy Eft,edgy,2006-06-01,2006-10-26,2008-04-26
 7.04,Feisty Fawn,feisty,2006-10-26,2007-04-19,2008-10-19
 7.10,Gutsy Gibbon,gutsy,2007-04-19,2007-10-18,2009-04-18
 8.04 LTS,Hardy Heron,hardy,2007-10-18,2008-04-24,2011-05-12,2013-05-09
 8.10,Intrepid Ibex,intrepid,2008-04-24,2008-10-30,2010-04-30
 9.04,Jaunty Jackalope,jaunty,2008-10-30,2009-04-23,2010-10-23
-9.10,Karmic Koala,karmic,2009-04-23,2009-10-29,2011-04-29
-10.04 LTS,Lucid Lynx,lucid,2009-10-29,2010-04-29,2013-05-09,2015-04-29
+9.10,Karmic Koala,karmic,2009-04-23,2009-10-29,2011-04-30
+10.04 LTS,Lucid Lynx,lucid,2009-10-29,2010-04-29,2013-05-09,2015-04-30
 10.10,Maverick Meerkat,maverick,2010-04-29,2010-10-10,2012-04-10
 11.04,Natty Narwhal,natty,2010-10-10,2011-04-28,2012-10-28
 11.10,Oneiric Ocelot,oneiric,2011-04-28,2011-10-13,2013-05-09
-12.04 LTS,Precise Pangolin,precise,2011-10-13,2012-04-26,2017-04-26
+12.04 LTS,Precise 
Pangolin,precise,2011-10-13,2012-04-26,2017-04-28,2017-04-28,2019-04-28
 12.10,Quantal Quetzal,quantal,2012-04-26,2012-10-18,2014-05-16
 13.04,Raring Ringtail,raring,2012-10-18,2013-04-25,2014-01-27
 13.10,Saucy Salamander,saucy,2013-04-25,2013-10-17,2014-07-17
-14.04 LTS,Trusty Tahr,trusty,2013-10-17,2014-04-17,2019-04-25
+14.04 LTS,Trusty 
Tahr,trusty,2013-10-17,2014-04-17,2019-04-25,2019-04-25,2022-04-25
 14.10,Utopic Unicorn,utopic,2014-04-17,2014-10-23,2015-07-23
-15.04,Vivid Vervet,vivid,2014-10-23,2015-04-23,2016-01-23
-15.10,Wily Werewolf,wily,2015-04-23,2015-10-22,2016-07-22
-16.04 LTS,Xenial Xerus,xenial,2015-10-22,2016-04-21,2021-04-21
+15.04,Vivid Vervet,vivid,2014-10-23,2015-04-23,2016-02-04
+15.10,Wily Werewolf,wily,2015-04-23,2015-10-22,2016-07-28
+16.04 LTS,Xenial 
Xerus,xenial,2015-10-22,2016-04-21,2021-04-21,2021-04-21,2024-04-21
 16.10,Yakkety Yak,yakkety,2016-04-21,2016-10-13,2017-07-20
 17.04,Zesty Zapus,zesty,2016-10-13,2017-04-13,2018-01-13
 17.10,Artful Aardvark,artful,2017-04-13,2017-10-19,2018-07-19
-18.04 LTS,Bionic Beaver,bionic,2017-10-19,2018-04-26,2023-04-26
+18.04 LTS,Bionic 
Beaver,bionic,2017-10-19,2018-04-26,2023-04-26,2023-04-26,2028-04-26
 18.10,Cosmic Cuttlefish,cosmic,2018-04-26,2018-10-18,2019-07-18
-19.04,Disco Dingo,disco,2018-10-18,2019-04-18,2020-01-18
+19.04,Disco Dingo,disco,2018-10-18,2019-04-18,2020-01-23
 19.10,Eoan Ermine,eoan,2019-04-18,2019-10-17,2020-07-17
-20.04 LTS,Focal Fossa,focal,2019-10-17,2020-04-23,2025-04-23
+20.04 LTS,Focal 
Fossa,focal,2019-10-17,2020-04-23,2025-04-23,2025-04-23,2030-04-23
 20.10,Groovy Gorilla,groovy,2020-04-23,2020-10-22,2021-07-22
 21.04,Hirsute Hippo,hirsute,2020-10-22,2021-04-22,2022-01-22
+21.10,Impish Indri,impish,2021-04-22,2021-10-14,2022-07-14
diff -Nru distro-info-data-0.41+deb10u3/up-to-date 
distro-info-data-0.47~deb10u1/up-to-date
--- distro-info-data-0.41+deb10u3/up-to-date    1969-12-31 20:00:00.000000000 
-0400
+++ distro-info-data-0.47~deb10u1/up-to-date    2021-04-22 11:46:22.000000000 
-0400
@@ -0,0 +1,81 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2012, Benjamin Drung <bdr...@debian.org>
+#               2018, Stefano Rivera <stefa...@debian.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""Validates that the data is up-to-date."""
+
+import csv
+import datetime
+import sys
+
+from lib.tools import convert_date, main
+
+ROLLING_FOREVER = {
+    "debian": ("sid", "experimental"),
+    "ubuntu": (),
+}
+
+
+def validate(filename, distro):
+    """Validates that the given CSV file is current.
+
+    Returns True if the given CSV file is current and otherwise False.
+    """
+    content = open(filename).readlines()
+    # Remove comments
+    for no, line in enumerate(content):
+        if line.startswith("#"):
+            content[no] = "\n"
+    csvreader = csv.DictReader(content)
+    today = datetime.datetime.utcnow().date()
+
+    last_release = None
+    dev_releases = []
+    for row in csvreader:
+        created = False
+        released = False
+        if row["series"] in ROLLING_FOREVER[distro]:
+            continue
+        if row["created"]:
+            created = today >= convert_date(row["created"])
+        if row["release"]:
+            released = today >= convert_date(row["release"])
+        if created:
+            if not released:
+                dev_releases.append(row["codename"])
+            else:
+                last_release = row["codename"]
+
+    if len(dev_releases) == 1:
+        return True
+
+    if len(dev_releases) > 1:
+        print(
+            "Multiple current development %s releases: %s" % (distro, 
dev_releases),
+            file=sys.stderr,
+        )
+    else:
+        print(
+            "No current development %s release. %s is now released."
+            % (distro, last_release),
+            file=sys.stderr,
+        )
+
+    return False
+
+
+if __name__ == "__main__":
+    sys.exit(main(validate))
diff -Nru distro-info-data-0.41+deb10u3/validate-csv-data 
distro-info-data-0.47~deb10u1/validate-csv-data
--- distro-info-data-0.41+deb10u3/validate-csv-data     2020-11-02 
16:44:14.000000000 -0400
+++ distro-info-data-0.47~deb10u1/validate-csv-data     2021-04-22 
11:46:22.000000000 -0400
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 # Copyright (C) 2012, Benjamin Drung <bdr...@debian.org>
 #
@@ -14,46 +14,58 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+# pylint: disable=invalid-name
+# pylint: enable=invalid-name
+
 """Validates a given Debian or Ubuntu distro-info CSV file."""
 
 import csv
-import datetime
-import optparse
-import os
 import sys
 
+from lib.tools import convert_date, main
+
+
 _COLUMNS = {
-    "debian": ("version", "codename", "series", "created", "release", "eol"),
-    "ubuntu": ("version", "codename", "series", "created", "release", "eol",
-               "eol-server"),
+    "debian": (
+        "version",
+        "codename",
+        "series",
+        "created",
+        "release",
+        "eol",
+        "eol-lts",
+        "eol-elts",
+    ),
+    "ubuntu": (
+        "version",
+        "codename",
+        "series",
+        "created",
+        "release",
+        "eol",
+        "eol-server",
+        "eol-esm",
+    ),
 }
-_DATES = ("created", "release", "eol", "eol-server")
+_DATES = ("created", "release", "eol", "eol-server", "eol-esm", "eol-lts", 
"eol-elts")
 _EARLIER_DATES = (
     ("created", "release"),
     ("release", "eol"),
     ("eol", "eol-server"),
+    ("eol", "eol-esm"),
+    ("eol", "eol-lts"),
+    ("eol-lts", "eol-elts"),
 )
 _STRINGS = {
     "debian": ("codename", "series"),
     "ubuntu": ("version", "codename", "series"),
 }
 
-def convert_date(string):
-    """Convert a date string in ISO 8601 into a datetime object."""
-    if not string:
-        date = None
-    else:
-        parts = [int(x) for x in string.split("-")]
-        if len(parts) == 3:
-            (year, month, day) = parts
-            date = datetime.date(year, month, day)
-        else:
-            raise ValueError("Date not in ISO 8601 format.")
-    return date
 
 def error(filename, line, message, *args):
     """Prints an error message"""
-    print >> sys.stderr, "%s:%i: %s." % (filename, line, message % args)
+    print("%s:%i: %s." % (filename, line, message % args), file=sys.stderr)
+
 
 def validate(filename, distro):
     """Validates a given CSV file.
@@ -63,9 +75,9 @@
     failures = 0
     content = open(filename).readlines()
     # Remove comments
-    for line in xrange(len(content)):
-        if content[line].startswith("#"):
-            content[line] = "\n"
+    for counter, line in enumerate(content):
+        if line.startswith("#"):
+            content[counter] = "\n"
     csvreader = csv.DictReader(content)
     for row in csvreader:
         # Check for missing columns
@@ -93,8 +105,7 @@
                     row[column] = convert_date(row[column])
                 except ValueError:
                     msg = "Invalid date `%s' in column `%s'"
-                    error(filename, csvreader.line_num, msg, row[column],
-                           column)
+                    error(filename, csvreader.line_num, msg, row[column], 
column)
                     failures += 1
                     row[column] = None
         # Check required date columns
@@ -108,51 +119,32 @@
             if date2 in row and row[date2]:
                 if date1 in row and row[date1]:
                     # date1 needs to be earlier than date2
-                    if row[date1] >= row[date2]:
-                        msg = ("Date %s of column `%s' needs to be later "
-                               "than %s of column `%s'")
-                        error(filename, csvreader.line_num, msg,
-                              row[date2].isoformat(), date2,
-                              row[date1].isoformat(), date1)
+                    if row[date1] > row[date2]:
+                        msg = (
+                            "Date %s of column `%s' needs to be >= "
+                            "than %s of column `%s'"
+                        )
+                        error(
+                            filename,
+                            csvreader.line_num,
+                            msg,
+                            row[date2].isoformat(),
+                            date2,
+                            row[date1].isoformat(),
+                            date1,
+                        )
                         failures += 1
                 else:
                     # date1 needs to be specified if date1 is specified
-                    msg = ("A date needs to be specified in column `%s' due "
-                           "to the given date in column `%s'")
+                    msg = (
+                        "A date needs to be specified in column `%s' due "
+                        "to the given date in column `%s'"
+                    )
                     error(filename, csvreader.line_num, msg, date1, date2)
                     failures += 1
 
     return failures == 0
 
-def main():
-    """Main function with command line parameter parsing."""
-    script_name = os.path.basename(sys.argv[0])
-    usage = "%s -d|-u csv-file" % (script_name)
-    parser = optparse.OptionParser(usage=usage)
-
-    parser.add_option("-d", "--debian", dest="debian", action="store_true",
-                      default=False, help="validate a Debian CSV file")
-    parser.add_option("-u", "--ubuntu", dest="ubuntu", action="store_true",
-                      default=False, help="validate an Ubuntu CSV file")
-
-    (options, args) = parser.parse_args()
-
-    if len(args) == 0:
-        parser.error("No CSV file specified.")
-    elif len(args) > 1:
-        parser.error("Multiple CSV files specified: %s" % (", ".join(args)))
-
-    if len([x for x in [options.debian, options.ubuntu] if x]) != 1:
-        parser.error("You have to select exactly one of --debian, --ubuntu.")
-    if options.debian:
-        distro = "debian"
-    else:
-        distro = "ubuntu"
-
-    if validate(args[0], distro):
-        return 0
-    else:
-        return 1
 
 if __name__ == "__main__":
-    sys.exit(main())
+    sys.exit(main(validate))
diff -Nru distro-info-data-0.41+deb10u3/debian/changelog 
distro-info-data-0.41+deb10u4/debian/changelog
--- distro-info-data-0.41+deb10u3/debian/changelog      2020-11-02 
16:44:14.000000000 -0400
+++ distro-info-data-0.41+deb10u4/debian/changelog      2021-04-22 
11:07:13.000000000 -0400
@@ -1,3 +1,13 @@
+distro-info-data (0.41+deb10u4) buster; urgency=medium
+
+  * Update data to 0.46, without new columns:
+    - Add estimated date for Buster EOL.
+    - Correct the EOL date for Debian Jessie.
+    - Add Debian 13 "Trixie", with a rough date.
+    - Add Ubuntu 21.04, Impish Indri.
+
+ -- Stefano Rivera <stefa...@debian.org>  Thu, 22 Apr 2021 11:07:13 -0400
+
 distro-info-data (0.41+deb10u3) buster; urgency=medium
 
   * Update data to 0.45:
diff -Nru distro-info-data-0.41+deb10u3/debian.csv 
distro-info-data-0.41+deb10u4/debian.csv
--- distro-info-data-0.41+deb10u3/debian.csv    2020-11-02 16:44:14.000000000 
-0400
+++ distro-info-data-0.41+deb10u4/debian.csv    2021-04-22 11:07:13.000000000 
-0400
@@ -11,10 +11,11 @@
 5.0,Lenny,lenny,2007-04-08,2009-02-14,2012-02-06
 6.0,Squeeze,squeeze,2009-02-14,2011-02-06,2014-05-31
 7,Wheezy,wheezy,2011-02-06,2013-05-04,2016-04-26
-8,Jessie,jessie,2013-05-04,2015-04-25,2018-06-06
+8,Jessie,jessie,2013-05-04,2015-04-25,2018-06-17
 9,Stretch,stretch,2015-04-25,2017-06-17,2020-07-06
-10,Buster,buster,2017-06-17,2019-07-06
+10,Buster,buster,2017-06-17,2019-07-06,2022-07-06
 11,Bullseye,bullseye,2019-07-06
 12,Bookworm,bookworm,2021-08-01
+13,Trixie,trixie,2023-08-01
 ,Sid,sid,1993-08-16
 ,Experimental,experimental,1993-08-16
diff -Nru distro-info-data-0.41+deb10u3/ubuntu.csv 
distro-info-data-0.41+deb10u4/ubuntu.csv
--- distro-info-data-0.41+deb10u3/ubuntu.csv    2020-11-02 16:44:14.000000000 
-0400
+++ distro-info-data-0.41+deb10u4/ubuntu.csv    2021-04-22 11:07:13.000000000 
-0400
@@ -33,3 +33,4 @@
 20.04 LTS,Focal Fossa,focal,2019-10-17,2020-04-23,2025-04-23
 20.10,Groovy Gorilla,groovy,2020-04-23,2020-10-22,2021-07-22
 21.04,Hirsute Hippo,hirsute,2020-10-22,2021-04-22,2022-01-22
+21.10,Impish Indri,impish,2021-04-22,2021-10-14,2022-07-14

Reply via email to