Import Upstream version 1.7

This commit is contained in:
luoyaoming 2024-04-30 16:35:30 +08:00
parent ed8521761a
commit f8c46ef62e
43 changed files with 1204 additions and 565 deletions

View File

@ -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"

11
debian/changelog vendored
View File

@ -1,11 +0,0 @@
distro-info (0.23-ok2) yangtze; urgency=low
* update version info
-- luzhiping <luzhiping@kylinos.cn> Mon, 22 Aug 2022 13:53:06 +0800
distro-info (0.23-ok1) yangtze; urgency=low
* Build for openKylin.
-- openKylinBot <openKylinBot@openkylin.com> Mon, 25 Apr 2022 22:03:04 +0800

51
debian/control vendored
View File

@ -1,51 +0,0 @@
Source: distro-info
Section: devel
Priority: optional
Maintainer: Openkylin Developers <packaging@lists.openkylin.top>
XSBC-Original-Maintainer: Benjamin Drung <bdrung@debian.org>
Uploaders: Stefano Rivera <stefanor@debian.org>
Build-Depends: debhelper-compat (= 12),
dh-python,
distro-info-data (>= 0.39ubuntu0),
pylint (>= 2.2.2-0),
python3-all,
python3-flake8,
python3-setuptools,
shunit2 (>= 2.1.6)
Standards-Version: 4.4.0
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.39ubuntu0), ${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
distribution. To get information about a specific distribution there are the
debian-distro-info and the ubuntu-distro-info scripts.
Package: libdistro-info-perl
Architecture: all
Section: perl
Depends: distro-info-data, ${misc:Depends}, ${perl:Depends}
Description: information about distributions' releases (Perl module)
Information about all releases of Debian and Ubuntu.
.
This package contains a Perl module for parsing the data in distro-info-data.
There is also a command line interface in the distro-info package.
Package: python3-distro-info
Architecture: all
Section: python
Depends: distro-info-data, ${misc:Depends}, ${python3:Depends}
Description: information about distributions' releases (Python 3 module)
Information about all releases of Debian and Ubuntu.
.
This package contains a Python 3 module for parsing the data in
distro-info-data. There is also a command line interface in the distro-info
package.

25
debian/copyright vendored
View File

@ -1,25 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: distro-info
Upstream-Contact: Benjamin Drung <bdrung@debian.org>
Files: *
Copyright: 2009-2018, Benjamin Drung <bdrung@debian.org>
2010-2011, Stefano Rivera <stefanor@debian.org>
License: ISC
Files: shell/*-distro-info.in shell/distro-info-util.sh
Copyright: 2012 Canonical Ltd.
License: ISC
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
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.

View File

@ -1,2 +0,0 @@
usr/bin
usr/share/man

View File

@ -1 +0,0 @@
usr/share/perl5

View File

@ -1 +0,0 @@
usr/lib/python3

6
debian/rules vendored
View File

@ -1,6 +0,0 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@ --with python3

View File

@ -1 +0,0 @@
3.0 (native)

15
debian/tests/control vendored
View File

@ -1,15 +0,0 @@
Test-Command: COMMAND=/usr/bin/debian-distro-info ./test-debian-distro-info
Depends: distro-info, shunit2 (>= 2.1.6)
Features: test-name=test-debian-distro-info
Test-Command: COMMAND=/usr/bin/ubuntu-distro-info ./test-ubuntu-distro-info
Depends: distro-info, shunit2 (>= 2.1.6)
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: pylint (>= 2.2.2-2~) | pylint3,
python3-all,
python3-distro-info,
python3-flake8
Restrictions: allow-stderr
Features: test-name=python3-unittest

View File

@ -17,6 +17,7 @@
// C standard libraries
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -38,6 +39,10 @@
static char *milestones[] = {"created"
,"release"
,"eol"
#ifdef DEBIAN
,"eol-lts"
,"eol-elts"
#endif
#ifdef UBUNTU
,"eol-server"
,"eol-esm"
@ -165,6 +170,37 @@ static date_t *read_date(const char *s, int *failures, const char *filename,
return date;
}
// Return current date. Take SOURCE_DATE_EPOCH into account.
// The result needs to be freed after its use.
static date_t *get_current_date() {
char *source_date_epoch, *endptr;
date_t *date;
unsigned long long epoch;
struct tm *now;
time_t time_now = 0;
source_date_epoch = getenv("SOURCE_DATE_EPOCH");
if (source_date_epoch != NULL) {
epoch = strtoull(source_date_epoch, &endptr, 10);
if (epoch > 0 && epoch < ULONG_MAX && *endptr == '\0') {
time_now = epoch;
} else {
fprintf(stderr, NAME ": Environment variable SOURCE_DATE_EPOCH"
"='%s' not a valid epoch. Ignoring.\n", source_date_epoch);
}
}
if (time_now == 0) {
time_now = time(NULL);
}
now = gmtime(&time_now);
date = malloc(sizeof(date_t));
date->year = 1900 + now->tm_year;
date->month = 1 + now->tm_mon;
date->day = now->tm_mday;
return date;
}
static inline bool date_ge(const date_t *date1, const date_t *date2) {
return date1->year > date2->year ||
(date1->year == date2->year && date1->month > date2->month) ||
@ -194,6 +230,20 @@ 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) {
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] &&
@ -220,6 +270,16 @@ static bool filter_supported(const date_t *date, const distro_t *distro) {
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) &&
@ -391,6 +451,10 @@ static void free_data(distro_elem_t *list, char **content) {
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]);
@ -417,9 +481,9 @@ static distro_elem_t *read_data(const char *filename, char **content) {
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++;
}
@ -545,19 +609,23 @@ static void print_help(void) {
#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"
" --supported list of all supported versions (including development)\n"
#ifdef DEBIAN
" -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
#ifdef DEBIAN
" -t --testing current testing version\n"
#endif
" --unsupported list of all unsupported stable versions\n"
" -c --codename print the codename (default)\n"
@ -573,9 +641,13 @@ static inline int not_exactly_one(void) {
"--alias, "
#endif
"--all, --devel, "
#ifdef UBUNTU
"--latest, --lts, "
#ifdef DEBIAN
"--elts, "
#endif
#ifdef UBUNTU
"--latest, "
#endif
"--lts, "
#ifdef DEBIAN
"--oldstable, "
#endif
@ -633,6 +705,8 @@ int main(int argc, char *argv[]) {
{"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
@ -647,7 +721,7 @@ int main(int argc, char *argv[]) {
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
@ -757,6 +831,18 @@ int main(int argc, char *argv[]) {
#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;
@ -870,12 +956,7 @@ int main(int argc, char *argv[]) {
}
if(unlikely(date == NULL)) {
time_t time_now = time(NULL);
struct tm *now = gmtime(&time_now);
date = malloc(sizeof(date_t));
date->year = 1900 + now->tm_year;
date->month = 1 + now->tm_mon;
date->day = now->tm_mday;
date = get_current_date();
}
distro_list = read_data(DATA_DIR "/" CSV_NAME ".csv", &content);

View File

@ -34,6 +34,10 @@
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
@ -71,6 +75,10 @@ static inline bool date_ge(const date_t *date1, const date_t *date2);
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

View File

@ -21,7 +21,8 @@ debian\-distro\-info \- provides information about Debian's distributions
.SH OPTIONS
.TP
\fB\-\-date\fR=\fIDATE
date for calculating the version (default: today)
date for calculating the version (default: epoch taken from SOURCE_DATE_EPOCH
environment variable if set, otherwise today)
.TP
\fB\-h\fR, \fB\-\-help\fR
display help message and exit
@ -63,7 +64,7 @@ series to calculate the version for
latest stable version
.TP
\fB\-\-supported\fR
list of all supported stable versions
list of all supported versions, including development releases
.TP
\fB\-t\fR, \fB\-\-testing\fR
latest testing version

View File

@ -31,7 +31,8 @@ specific.
.SH OPTIONS
.TP
\fB\-\-date\fR=\fIDATE
date for calculating the version (default: today)
date for calculating the version (default: epoch taken from SOURCE_DATE_EPOCH
environment variable if set, otherwise today)
.TP
\fB\-h\fR, \fB\-\-help\fR
display help message and exit
@ -61,7 +62,7 @@ series to calculate the version for
latest stable version
.TP
\fB\-\-supported\fR
list of all supported stable versions
list of all supported versions, including development releases
.TP
\fB\-\-unsupported\fR
list of all unsupported stable versions

View File

@ -21,7 +21,8 @@ ubuntu\-distro\-info \- provides information about Ubuntu's distributions
.SH OPTIONS
.TP
\fB\-\-date\fR=\fIDATE
date for calculating the version (default: today)
date for calculating the version (default: epoch taken from SOURCE_DATE_EPOCH
environment variable if set, otherwise today)
.TP
\fB\-h\fR, \fB\-\-help\fR
display help message and exit
@ -64,7 +65,10 @@ series to calculate the version for
latest stable version
.TP
\fB\-\-supported\fR
list of all supported stable versions
list of all supported versions, including the development release
.TP
\fB\-\-supported\-esm\fR
list of all Ubuntu Advantage supported stable versions
.TP
\fB\-\-unsupported\fR
list of all unsupported stable versions

View File

@ -21,7 +21,6 @@ import System.Console.GetOpt
import System.Environment
import System.Exit
import System.IO
import System.Locale
import Text.CSV
@ -47,8 +46,8 @@ startOptions = do
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 @@ options =
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 @@ options =
"list all known versions"
, Option "d" ["devel"] (NoArg (setFilter debianDevel))
"latest development version"
, Option "o" ["oldstable"] (NoArg (setFilter debianOldstable))
"latest oldstable version"
, Option "s" ["stable"] (NoArg (setFilter debianStable))
"latest stable version"
, Option "" ["supported"] (NoArg (setFilter debianSupported))
"list of all supported stable versions"
, 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 versions (including development)"
, 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"]

View File

@ -20,6 +20,8 @@ module DistroInfo (DebianEntry, debVersion, debSeries, debFull,
debianOldstable,
debianStable,
debianSupported,
debianSupportedLTS,
debianSupportedELTS,
debianTesting,
debianUnsupported,
UbuntuEntry, ubuVersion, ubuSeries, ubuFull,
@ -29,6 +31,7 @@ module DistroInfo (DebianEntry, debVersion, debSeries, debFull,
ubuntuLTS,
ubuntuStable,
ubuntuSupported,
ubuntuSupportedESM,
ubuntuUnsupported,
) where
@ -46,7 +49,9 @@ data DebianEntry = DebianEntry { debVersion :: String,
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 @@ data UbuntuEntry = UbuntuEntry { ubuVersion :: String,
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 @@ ubuntuEntry (heading : content) =
(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 @@ debianEntry (heading : content) =
(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 @@ debianSupported date = filter isSupported
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 @@ ubuntuSupported date = filter isSupported
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

View File

@ -26,6 +26,10 @@ import DistroInfo
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 @@ testDebianSupported d = TestCase (assertEqual "Debian supported" expected result
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 @@ testUbuntuSupported u = TestCase (assertEqual "Ubuntu supported" expected result
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 :: [DebianEntry] -> [UbuntuEntry] -> Test
tests d u = TestList [
testDebianAll d,
testDebianDevel d,
testDebianSupportedLTS d,
testDebianSupportedELTS d,
testDebianOldstable d,
testDebianStable d,
testDebianSupported d,
@ -136,6 +160,7 @@ tests d u = TestList [
testUbuntuLTS u,
testUbuntuStable u,
testUbuntuSupported u,
testUbuntuSupportedESM u,
testUbuntuUnsupported u
]

View File

@ -21,7 +21,6 @@ import System.Console.GetOpt
import System.Environment
import System.Exit
import System.IO
import System.Locale
import Text.CSV
@ -47,13 +46,14 @@ startOptions = do
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 @@ options =
"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"
"list of all supported versions (including development)"
, 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"]

View File

@ -77,7 +77,8 @@ sub convert_date {
for my $col (@header) {
$row{$col} = shift(@raw_row) or undef;
}
for my $col ('created', 'release', 'eol', 'eol-server', 'eol-esm') {
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 @@ sub convert_date {
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));

View File

@ -1,5 +1,5 @@
#!/usr/bin/perl
# Copyright (C) 2011-2012, Stefano Rivera <stefanor@debian.org>
# Copyright (C) 2011-2019, Stefano Rivera <stefanor@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 @@ ok(symmetric_difference(\@all, \@returned) == 1,
# 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 @@ ok($deb->version('lenny') eq '5.0', 'Debian version');
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(42), 'Ubuntu !is_lts');
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');

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
# Copyright (C) 2009-2011, Benjamin Drung <bdrung@debian.org>
#
@ -23,50 +23,89 @@ import argparse
import os
import sys
from distro_info import convert_date, DebianDistroInfo
from distro_info import DebianDistroInfo, convert_date
def parse_args():
script_name = os.path.basename(sys.argv[0])
usage = "%s [options]" % (script_name)
epilog = "See %s(1) for more info." % (script_name)
usage = f"{script_name} [options]"
epilog = f"See {script_name}(1) for more info."
parser = argparse.ArgumentParser(usage=usage, epilog=epilog)
parser.add_argument("--date", dest="date", default=None,
help="date for calculating the version (default: today).")
parser.add_argument("-a", "--all", dest="all", action="store_true",
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("-s", "--stable", dest="stable", action="store_true",
help="latest 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("--unsupported", dest="unsupported",
help="list of all unsupported stable versions")
parser.add_argument(
"--date",
dest="date",
default=None,
help="date for calculating the version (default: today).",
)
parser.add_argument(
"-a", "--all", dest="all", action="store_true", help="list all known versions"
)
parser.add_argument(
"-d", "--devel", dest="devel", action="store_true", help="latest development 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 versions (including development)",
)
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:
args.date = convert_date(args.date)
except ValueError:
parser.error("Option --date needs to be a date in ISO 8601 "
"format.")
parser.error("Option --date needs to be a date in ISO 8601 format.")
return args
def main():
# pylint: disable=too-many-branches
args = parse_args()
if args.all:
for distro in DebianDistroInfo().all:
@ -80,6 +119,12 @@ def main():
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:

View File

@ -17,29 +17,24 @@
import csv
import datetime
import os
import typing
def convert_date(string):
def convert_date(string: str) -> datetime.date:
"""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)
elif len(parts) == 2:
(year, month) = parts
if month == 12:
date = datetime.date(year, month, 31)
else:
date = datetime.date(year, month + 1, 1) - datetime.timedelta(1)
else:
raise ValueError("Date not in ISO 8601 format.")
return date
parts = [int(x) for x in string.split("-")]
if len(parts) == 3:
(year, month, day) = parts
return datetime.date(year, month, day)
if len(parts) == 2:
(year, month) = parts
if month == 12:
return datetime.date(year, month, 31)
return datetime.date(year, month + 1, 1) - datetime.timedelta(1)
raise ValueError("Date not in ISO 8601 format.")
def _get_data_dir():
def _get_data_dir() -> str:
"""Get the data directory based on the module location."""
return "/usr/share/distro-info"
@ -47,20 +42,32 @@ def _get_data_dir():
class DistroDataOutdated(Exception):
"""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.")
def __init__(self) -> None:
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):
class DistroRelease:
"""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, eol_esm=None):
def __init__(
self,
version: str,
codename: str,
series: str,
created: datetime.date,
release: typing.Optional[datetime.date] = None,
eol: typing.Optional[datetime.date] = None,
eol_esm: typing.Optional[datetime.date] = None,
eol_lts: typing.Optional[datetime.date] = None,
eol_elts: typing.Optional[datetime.date] = None,
eol_server: typing.Optional[datetime.date] = None,
) -> None:
# pylint: disable=too-many-arguments
self.version = version
self.codename = codename
@ -68,75 +75,102 @@ class DistroRelease(object):
self.created = created
self.release = release
self.eol = eol
self.eol_server = eol_server
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):
def is_supported(self, date: datetime.date) -> bool:
"""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):
return convert_date(row[column]) if column in row else None
def _get_date(row: dict[str, str], column: str) -> typing.Optional[datetime.date]:
date_string = row.get(column)
if not date_string:
return None
return convert_date(date_string)
class DistroInfo(object):
class DistroInfo:
"""Base class for distribution information.
Use DebianDistroInfo or UbuntuDistroInfo instead of using this directly.
"""
def __init__(self, distro):
def __init__(self, distro: str) -> None:
self._distro = distro
filename = os.path.join(_get_data_dir(), distro.lower() + ".csv")
csvfile = open(filename)
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'),
_get_date(row, 'eol-esm'))
self._releases.append(release)
csvfile.close()
with open(filename, encoding="utf-8") as csvfile:
csv_reader = csv.DictReader(csvfile)
self._releases = []
for row in csv_reader:
release = DistroRelease(
row["version"],
row["codename"],
row["series"],
convert_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)
self._date = datetime.date.today()
@property
def all(self):
def all(self) -> list[str]:
"""List codenames of all known distributions."""
return [x.series for x in self._releases]
def get_all(self, result="codename"):
def get_all(self, result: str = "codename") -> list[typing.Union[DistroRelease, str]]:
"""List all known distributions."""
return [self._format(result, x) for x in self._releases]
def _avail(self, date):
def _avail(self, date: datetime.date) -> list[DistroRelease]:
"""Return all distributions that were available on the given date."""
return [x for x in self._releases if date >= x.created]
def codename(self, release, date=None, default=None):
def codename(
self,
release: str,
date: typing.Optional[datetime.date] = None,
default: typing.Optional[str] = None,
) -> typing.Union[DistroRelease, str, None]:
"""Map codename aliases to the codename they describe."""
# pylint: disable=no-self-use,unused-argument
return release
def version(self, name, default=None):
def version(self, name: str, default: typing.Optional[str] = None) -> typing.Optional[str]:
"""Map codename or series to version"""
for release in self._releases:
if name in (release.codename, release.series):
return release.version
return default
def devel(self, date=None, result="codename"):
def devel(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> typing.Union[DistroRelease, str]:
"""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])
def _format(self, format_string, release):
def _format(
self, format_string: str, release: DistroRelease
) -> typing.Union[DistroRelease, str]:
"""Format a given distribution entry."""
if format_string == "object":
return release
@ -147,142 +181,217 @@ class DistroInfo(object):
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"):
def stable(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> typing.Union[DistroRelease, str]:
"""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])
def supported(self, date=None, result=None):
def supported(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> list[typing.Union[DistroRelease, str]]:
"""Get list of all supported distributions based on the given date."""
raise NotImplementedError()
def valid(self, codename):
def valid(self, codename: str) -> bool:
"""Check if the given codename is known."""
return codename in self.all
def unsupported(self, date=None, result="codename"):
def unsupported(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> list[typing.Union[DistroRelease, str]]:
"""Get list of all unsupported distributions based on the given date."""
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
class DebianDistroInfo(DistroInfo):
"""provides information about Debian's distributions"""
def __init__(self):
super(DebianDistroInfo, self).__init__("Debian")
def __init__(self) -> None:
super().__init__("Debian")
def codename(self, release, date=None, default=None):
def codename(
self,
release: str,
date: typing.Optional[datetime.date] = None,
default: typing.Optional[str] = None,
) -> typing.Union[DistroRelease, str, None]:
"""Map 'unstable', 'testing', etc. to their codenames."""
if release == "unstable":
codename = self.devel(date)
elif release == "testing":
codename = self.testing(date)
elif release == "stable":
codename = self.stable(date)
elif release == "oldstable":
codename = self.old(date)
else:
codename = default
return codename
return self.devel(date)
if release == "testing":
return self.testing(date)
if release == "stable":
return self.stable(date)
if release == "oldstable":
return self.old(date)
return default
def devel(self, date=None, result="codename"):
def devel(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> typing.Union[DistroRelease, str]:
"""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])
def old(self, date=None, result="codename"):
def old(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> typing.Union[DistroRelease, str]:
"""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"):
def supported(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> list[typing.Union[DistroRelease, str]]:
"""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 testing(self, date=None, result="codename"):
def lts_supported(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> list[typing.Union[DistroRelease, str]]:
"""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: typing.Optional[datetime.date] = None, result: str = "codename"
) -> list[typing.Union[DistroRelease, str]]:
"""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: typing.Optional[datetime.date] = None, result: str = "codename"
) -> typing.Union[DistroRelease, str]:
"""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):
def valid(self, codename: str) -> bool:
"""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")
def __init__(self) -> None:
super().__init__("Ubuntu")
def lts(self, date=None, result="codename"):
def lts(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> typing.Union[DistroRelease, str]:
"""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 and x.eol and x.release <= date <= x.eol
]
if not distros:
raise DistroDataOutdated()
return self._format(result, distros[-1])
def is_lts(self, codename):
def is_lts(self, codename: str) -> bool:
"""Is codename an LTS release?"""
distros = [x for x in self._releases if x.series == codename]
if not distros:
return False
return "LTS" in distros[0].version
def supported(self, date=None, result="codename"):
def supported(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> list[typing.Union[DistroRelease, str]]:
"""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)]
distros = [
self._format(result, x)
for x in self._avail(date)
if (x.eol and 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"):
def supported_esm(
self, date: typing.Optional[datetime.date] = None, result: str = "codename"
) -> list[typing.Union[DistroRelease, str]]:
"""Get list of all ESM supported Ubuntu distributions based on the
given date."""
given date."""
if date is None:
date = self._date
distros = [self._format(result, x) for x in self._avail(date)
if x.eol_esm is not None and date <= x.eol_esm]
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

View File

View File

@ -1,4 +1,4 @@
# Copyright (C) 2017, Benjamin Drung <benjamin.drung@profitbricks.com>
# Copyright (C) 2017-2021, Benjamin Drung <benjamin.drung@ionos.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@ -12,46 +12,47 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Test suite for distro-info"""
"""Helper functions for testing."""
import inspect
import os
import site
import sys
import unittest
def get_source_files():
"""Return a list of sources files/directories (to check with flake8/pylint)"""
def get_source_files() -> list[str]:
"""Return a list of sources files/directories (to check with flake8/pylint)."""
scripts = ["debian-distro-info", "ubuntu-distro-info"]
modules = []
modules = ["distro_info_test"]
py_files = ["distro_info.py", "setup.py"]
files = []
for code_file in scripts + modules + py_files:
is_script = code_file in scripts
if not os.path.exists(code_file): # pragma: no cover
# The alternative path in the OLDPWD environment is needed for Debian's pybuild
# Use installed files as fallback
for alternative_path in [os.environ.get("OLDPWD", "")] + site.getsitepackages():
alternative = os.path.join(alternative_path, code_file)
if os.path.exists(alternative):
code_file = alternative
break
# The alternative path is needed for Debian's pybuild
alternative = os.path.join(os.environ.get("OLDPWD", ""), code_file)
code_file = alternative if os.path.exists(alternative) else code_file
if (
not os.path.exists(code_file)
and code_file.endswith(".py")
and "AUTOPKGTEST_TMP" in os.environ
):
code_file = "/usr/lib/python3/dist-packages/" + code_file
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 "python" in shebang:
files.append(code_file)
else:
files.append(code_file)
return files
def unittest_verbosity():
"""Return the verbosity setting of the currently running unittest
program, or None if none is running.
def unittest_verbosity() -> int:
"""
Return the verbosity setting of the currently running unittest.
If no test is running, return 0.
"""
frame = inspect.currentframe()
while frame:
@ -59,4 +60,4 @@ def unittest_verbosity():
if isinstance(self, unittest.TestProgram):
return self.verbosity
frame = frame.f_back
return None # pragma: no cover
return 0 # pragma: no cover

View File

@ -1,8 +1,9 @@
[MASTER]
[MAIN]
# Pickle collected data for later comparisons.
persistent=no
load-plugins=pylint.extensions.no_self_use
[MESSAGES CONTROL]
@ -15,7 +16,7 @@ persistent=no
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=locally-disabled,locally-enabled,missing-docstring,useless-object-inheritance
disable=locally-disabled,missing-docstring
[REPORTS]
@ -37,4 +38,4 @@ indent-string=' '
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=11
min-similarity-lines=15

View File

@ -0,0 +1,41 @@
# Copyright (C) 2021, Benjamin Drung <bdrung@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.
"""Run black code formatter in check mode."""
import subprocess
import sys
import unittest
from . import get_source_files, unittest_verbosity
class BlackTestCase(unittest.TestCase):
"""
This unittest class provides a test that runs the black code
formatter in check mode on the Python source code. The list of
source files is provided by the get_source_files() function.
"""
def test_black(self) -> None:
"""Test: Run black code formatter on Python source code."""
cmd = ["black", "--check", "--diff", "-l", "99"] + get_source_files()
if unittest_verbosity() >= 2:
sys.stderr.write(f"Running following command:\n{' '.join(cmd)}\n")
process = subprocess.run(cmd, capture_output=True, check=False, text=True)
if process.returncode == 1: # pragma: no cover
self.fail(f"black found code that needs reformatting:\n{process.stdout.strip()}")
if process.returncode != 0: # pragma: no cover
self.fail(f"black exited with code {process.returncode}:\n{process.stdout.strip()}")

View File

@ -25,159 +25,188 @@ from distro_info import DebianDistroInfo, UbuntuDistroInfo
class DebianDistroInfoTestCase(unittest.TestCase): # pylint: disable=too-many-public-methods
"""TestCase object for distro_info.DebianDistroInfo"""
def setUp(self): # pylint: disable=invalid-name
def setUp(self) -> None: # pylint: disable=invalid-name
self._distro_info = DebianDistroInfo()
self._date = datetime.date(2011, 1, 10)
def test_all(self):
def test_all(self) -> None:
"""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):
def test_devel(self) -> None:
"""Test: Get latest development Debian distribution."""
self.assertEqual(self._distro_info.devel(self._date), "sid")
def test_old(self):
def test_old(self) -> None:
"""Test: Get old (stable) Debian distribution."""
self.assertEqual(self._distro_info.old(self._date), "etch")
def test_stable(self):
def test_stable(self) -> None:
"""Test: Get latest stable Debian distribution."""
self.assertEqual(self._distro_info.stable(self._date), "lenny")
def test_supported(self):
def test_supported(self) -> None:
"""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_testing(self):
def test_lts_supported(self) -> None:
"""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) -> None:
"""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) -> None:
"""Test: Get latest testing Debian distribution."""
self.assertEqual(self._distro_info.testing(self._date), "squeeze")
def test_valid(self):
def test_valid(self) -> None:
"""Test: Check for valid Debian distribution."""
self.assertTrue(self._distro_info.valid("sid"))
self.assertTrue(self._distro_info.valid("stable"))
self.assertFalse(self._distro_info.valid("foobar"))
def test_unsupported(self):
def test_unsupported(self) -> None:
"""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):
def test_codename(self) -> None:
"""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):
def test_version(self) -> None:
"""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):
def test_codename_result(self) -> None:
"""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):
def test_fullname(self) -> None:
"""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):
def test_release(self) -> None:
"""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
"""TestCase object for distro_info.UbuntuDistroInfo"""
def setUp(self): # pylint: disable=invalid-name
def setUp(self) -> None: # pylint: disable=invalid-name
self._distro_info = UbuntuDistroInfo()
self._date = datetime.date(2011, 1, 10)
def test_all(self):
def test_all(self) -> None:
"""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):
def test_devel(self) -> None:
"""Test: Get latest development Ubuntu distribution."""
self.assertEqual(self._distro_info.devel(self._date), "natty")
def test_lts(self):
def test_lts(self) -> None:
"""Test: Get latest long term support (LTS) Ubuntu distribution."""
self.assertEqual(self._distro_info.lts(self._date), "lucid")
def test_stable(self):
def test_stable(self) -> None:
"""Test: Get latest stable Ubuntu distribution."""
self.assertEqual(self._distro_info.stable(self._date), "maverick")
def test_supported(self):
def test_supported(self) -> None:
"""Test: List all supported Ubuntu distribution."""
supported = ["dapper", "hardy", "karmic", "lucid", "maverick", "natty"]
self.assertEqual(self._distro_info.supported(self._date), supported)
def test_unsupported(self):
def test_unsupported(self) -> None:
"""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):
def test_current_unsupported(self) -> None:
"""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(str(d) for d in self._distro_info.unsupported()), set())
def test_valid(self):
def test_valid(self) -> None:
"""Test: Check for valid Ubuntu distribution."""
self.assertTrue(self._distro_info.valid("lucid"))
self.assertFalse(self._distro_info.valid("42"))
def test_is_lts(self):
def test_is_lts(self) -> None:
"""Test: Check if Ubuntu distribution is an LTS."""
self.assertTrue(self._distro_info.is_lts("lucid"))
self.assertFalse(self._distro_info.is_lts("42"))
self.assertFalse(self._distro_info.is_lts("warty"))
def test_codename(self):
def test_codename(self) -> None:
"""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):
def test_version(self) -> None:
"""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):
def test_fullname(self) -> None:
"""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):
def test_release(self) -> None:
"""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")

View File

@ -12,7 +12,7 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""test_flake8.py - Run flake8 check"""
"""Run flake8 check."""
import subprocess
import sys
@ -29,23 +29,25 @@ class Flake8TestCase(unittest.TestCase):
get_source_files() function.
"""
def test_flake8(self):
"""Test: Run flake8 on Python source code"""
cmd = [sys.executable, "-m", "flake8", "--ignore", "H301,H403,H405,W504", "--max-line-length=99"] + get_source_files()
def test_flake8(self) -> None:
"""Test: Run flake8 on Python source code."""
cmd = [sys.executable, "-m", "flake8", "--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)
sys.stderr.write(f"Running following command:\n{' '.join(cmd)}\n")
process = subprocess.run(cmd, capture_output=True, check=False, text=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()))
if out:
msgs.append("flake8 found issues:\n{}".format(out.decode().rstrip()))
if process.stderr:
msgs.append(
f"flake8 exited with code {process.returncode} and has"
f" unexpected output on stderr:\n{process.stderr.rstrip()}"
)
if process.stdout:
msgs.append(f"flake8 found issues:\n{process.stdout.rstrip()}")
if not msgs:
msgs.append("flake8 exited with code {} and has no output on stdout or stderr."
.format(process.returncode))
msgs.append(
f"flake8 exited with code {process.returncode} "
"and has no output on stdout or stderr."
)
self.fail("\n".join(msgs))

View File

@ -20,52 +20,60 @@ import select
import signal
import subprocess
import time
import typing
import unittest
import setup
from distro_info_test import unittest
TIMEOUT = 5
class HelpTestCase(unittest.TestCase):
@classmethod
def populate(cls):
def populate(cls) -> None:
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)
started = time.time()
out = []
def make_help_tester(cls, script: str) -> typing.Callable[[typing.Any], None]:
def tester(self: typing.Any) -> None:
with subprocess.Popen(
["./" + script, "--help"],
close_fds=True,
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
) as process:
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)
assert process.stdout
assert process.stderr
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,
)
while time.time() - started < TIMEOUT:
for file_descriptor in select.select(fds, [], fds, TIMEOUT)[0]:
out.append(os.read(file_descriptor, 1024))
if process.poll() is not None:
break
while time.time() - started < TIMEOUT:
for file_descriptor in select.select(fds, [], fds, TIMEOUT)[0]:
out.append(os.read(file_descriptor, 1024))
if process.poll() is not None:
break
if process.poll() is None:
os.kill(process.pid, signal.SIGTERM)
time.sleep(1)
if process.poll() is None:
os.kill(process.pid, signal.SIGKILL)
null.close()
os.kill(process.pid, signal.SIGTERM)
time.sleep(1)
if process.poll() is None:
os.kill(process.pid, signal.SIGKILL)
self.assertEqual(
process.poll(),
0,
f"{script} failed to return usage within {TIMEOUT} seconds.\n"
f"Output:\n{b''.join(out).decode()}",
)
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

View File

@ -0,0 +1,39 @@
# Copyright (C) 2021, Benjamin Drung <bdrung@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.
"""Run isort to check if Python import definitions are sorted."""
import subprocess
import sys
import unittest
from . import get_source_files, unittest_verbosity
class IsortTestCase(unittest.TestCase):
"""
This unittest class provides a test that runs isort to check if
Python import definitions are sorted. The list of source files
is provided by the get_source_files() function.
"""
def test_isort(self) -> None:
"""Test: Run isort on Python source code."""
cmd = ["isort", "--check-only", "--diff", "-l", "99"] + get_source_files()
if unittest_verbosity() >= 2:
sys.stderr.write(f"Running following command:\n{' '.join(cmd)}\n")
process = subprocess.run(cmd, capture_output=True, check=False, text=True)
if process.returncode != 0: # pragma: no cover
self.fail(f"isort found unsorted Python import definitions:\n{process.stdout.strip()}")

View File

@ -0,0 +1,61 @@
# Copyright (C) 2023, Benjamin Drung <bdrung@ubuntu.com>
#
# 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.
"""Run mypy to check static typing of the Python code."""
import shutil
import subprocess
import sys
import unittest
from . import get_source_files, unittest_verbosity
class MypyTestCase(unittest.TestCase):
"""
This unittest class provides a test that runs mypy to check static
typing of the Python code. The list of source files is provided by
the get_source_files() function.
"""
@unittest.skipIf(not shutil.which("mypy"), "mypy not found")
def test_mypy(self) -> None:
"""Test: Run mypy on Python source code."""
# The *-distro-info binaries do not have type hints.
# Exlude system installed modules due to https://github.com/python/mypy/issues/14559
sources = [
s for s in get_source_files() if not (s.endswith("-distro-info") or s.startswith("/"))
]
# PEP 561 does not support distributing typing information as part of module-only
# distributions. So suppress errors for missing type hints of installed `distro_info`.
cmd = ["mypy", "--ignore-missing-imports", "--strict"] + sources
if unittest_verbosity() >= 2:
sys.stderr.write(f"Running following command:\n{' '.join(cmd)}\n")
process = subprocess.run(cmd, capture_output=True, check=False, text=True)
if process.returncode != 0: # pragma: no cover
msgs = []
if process.stderr:
msgs.append(
f"mypy exited with code {process.returncode} and has"
f" unexpected output on stderr:\n{process.stderr.rstrip()}"
)
if process.stdout:
msgs.append(f"mypy found issues:\n{process.stdout.rstrip()}")
if not msgs:
msgs.append(
f"mypy exited with code {process.returncode} "
"and has no output on stdout or stderr."
)
self.fail("\n".join(msgs))

View File

@ -13,7 +13,7 @@
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
"""test_pylint.py - Run pylint"""
"""Run pylint."""
import os
import re
@ -34,15 +34,12 @@ class PylintTestCase(unittest.TestCase):
a config file.
"""
def test_pylint(self):
"""Test: Run pylint on Python source code"""
cmd = [sys.executable, "-m", "pylint", "--rcfile=" + CONFIG, "--"] + get_source_files()
def test_pylint(self) -> None:
"""Test: Run pylint on Python source code."""
cmd = ["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)
out, err = process.communicate()
sys.stderr.write(f"Running following command:\n{' '.join(cmd)}\n")
process = subprocess.run(cmd, capture_output=True, check=False, text=True)
if process.returncode != 0: # pragma: no cover
# Strip trailing summary (introduced in pylint 1.7). This summary might look like:
@ -50,19 +47,24 @@ class PylintTestCase(unittest.TestCase):
# ------------------------------------
# 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 .*)$", "", process.stdout, 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()
err = re.sub("^Using config file .*\n", "", process.stderr.rstrip())
msgs = []
if err:
msgs.append("pylint exited with code {} and has unexpected output on stderr:\n{}"
.format(process.returncode, err))
msgs.append(
f"pylint exited with code {process.returncode} "
f"and has unexpected output on stderr:\n{err}"
)
if out:
msgs.append("pylint found issues:\n{}".format(out))
msgs.append(f"pylint found issues:\n{out}")
if not msgs:
msgs.append("pylint exited with code {} and has no output on stdout or stderr."
.format(process.returncode))
msgs.append(
f"pylint exited with code {process.returncode} "
"and has no output on stdout or stderr."
)
self.fail("\n".join(msgs))

View File

@ -0,0 +1,58 @@
# Copyright (C) 2022, Benjamin Drung <bdrung@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.
"""Test functions in setup.py."""
import unittest
import unittest.mock
from setup import make_pep440_compliant
class SetupTestCase(unittest.TestCase):
"""Test functions in setup.py."""
def test_make_pep440_compliant_unchanged(self) -> None:
"""Test make_pep440_compliant() with already correct version."""
self.assertEqual(make_pep440_compliant("1.2"), "1.2")
def test_make_pep440_compliant_debian_backport(self) -> None:
"""Test make_pep440_compliant() with Debian backport version."""
self.assertEqual(make_pep440_compliant("0.21~bpo9+1"), "0.21+bpo9.1")
def test_make_pep440_compliant_debian_stable(self) -> None:
"""Test make_pep440_compliant() with Debian stable update."""
self.assertEqual(make_pep440_compliant("2.21.3+deb11u1"), "2.21.3+deb11u1")
def test_make_pep440_compliant_debian_stable_backport(self) -> None:
"""Test make_pep440_compliant() with Debian stable backport."""
self.assertEqual(make_pep440_compliant("2.21.3+deb11u1~bpo10+1"), "2.21.3+deb11u1.bpo10.1")
def test_make_pep440_compliant_tilde(self) -> None:
"""Test make_pep440_compliant() with tilde in Debian version."""
self.assertEqual(make_pep440_compliant("0.175~18.04.3"), "0.175+18.04.3")
def test_make_pep440_compliant_ubuntu(self) -> None:
"""Test make_pep440_compliant() with Ubuntu version."""
self.assertEqual(make_pep440_compliant("1.1ubuntu1"), "1.1+ubuntu1")
def test_make_pep440_compliant_ubuntu_backport(self) -> None:
"""Test make_pep440_compliant() with Ubuntu backport version."""
self.assertEqual(
make_pep440_compliant("2.22.1ubuntu1~bpo20.04.1"), "2.22.1+ubuntu1.bpo20.04.1"
)
def test_make_pep440_compliant_ubuntu_security(self) -> None:
"""Test make_pep440_compliant() with Ubuntu security update."""
self.assertEqual(make_pep440_compliant("2.17.12ubuntu1.1"), "2.17.12+ubuntu1.1")

View File

@ -1,36 +1,47 @@
#!/usr/bin/python
#!/usr/bin/python3
import os
import pathlib
import re
from setuptools import setup
PACKAGES = []
PY_MODULES = ['distro_info']
SCRIPTS = [
'debian-distro-info',
'ubuntu-distro-info',
]
PACKAGES = ["distro_info"]
PY_MODULES = ["distro_info"]
SCRIPTS = ["debian-distro-info", "ubuntu-distro-info"]
def get_debian_version():
def get_debian_version() -> str:
"""look what Debian version we have"""
version = None
changelog = "../debian/changelog"
if os.path.exists(changelog):
head = open(changelog, "rb").readline().decode("utf-8")
match = re.compile(r".*\((.*)\).*").match(head)
if match:
version = match.group(1)
return version
changelog = pathlib.Path(__file__).parent.parent / "debian" / "changelog"
with changelog.open("r", encoding="utf-8") as changelog_f:
head = changelog_f.readline()
match = re.compile(r".*\((.*)\).*").match(head)
if not match:
raise ValueError(f"Failed to extract Debian version from '{head}'.")
return match.group(1)
if __name__ == '__main__':
def make_pep440_compliant(version: str) -> str:
"""Convert the version into a PEP440 compliant version."""
public_version_re = re.compile(r"^([0-9][0-9.]*(?:(?:a|b|rc|.post|.dev)[0-9]+)*)\+?")
_, public, local = public_version_re.split(version, maxsplit=1)
if not local:
return version
sanitized_local = re.sub("[+~]+", ".", local).strip(".")
pep440_version = f"{public}+{sanitized_local}"
assert re.match("^[a-zA-Z0-9.]+$", sanitized_local), f"'{pep440_version}' not PEP440 compliant"
return pep440_version
if __name__ == "__main__":
setup(
name='distro-info',
version=get_debian_version(),
name="distro-info",
version=make_pep440_compliant(get_debian_version()),
py_modules=PY_MODULES,
packages=PACKAGES,
test_suite="distro_info_test",
url="https://salsa.debian.org/debian/distro-info",
author="Benjamin Drung",
author_email="bdrung@debian.org",
package_data={"distro_info": ["py.typed"]},
)

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
# Copyright (C) 2009-2011, Benjamin Drung <bdrung@debian.org>
#
@ -23,49 +23,65 @@ import argparse
import os
import sys
from distro_info import convert_date, UbuntuDistroInfo
from distro_info import UbuntuDistroInfo, convert_date
def parse_args():
def parse_args() -> argparse.Namespace:
script_name = os.path.basename(sys.argv[0])
usage = "%s [options]" % (script_name)
epilog = "See %s(1) for more info." % (script_name)
usage = f"{script_name} [options]"
epilog = f"See {script_name}(1) for more info."
parser = argparse.ArgumentParser(usage=usage, epilog=epilog)
parser.add_argument("--date", dest="date", default=None,
help="date for calculating the version (default: today).")
parser.add_argument("-a", "--all", dest="all", action="store_true",
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("--supported", dest="supported", action="store_true",
help="list of all supported stable versions")
parser.add_argument("--unsupported", dest="unsupported", action="store_true",
help="list of all unsupported stable versions")
parser.add_argument(
"--date",
dest="date",
default=None,
help="date for calculating the version (default: today).",
)
parser.add_argument(
"-a", "--all", dest="all", action="store_true", help="list all known versions"
)
parser.add_argument(
"-d", "--devel", dest="devel", action="store_true", help="latest development 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 versions (including development)",
)
parser.add_argument(
"--unsupported",
dest="unsupported",
action="store_true",
help="list of all unsupported stable versions",
)
args = parser.parse_args()
versions = [args.all, args.devel, args.lts, args.stable,
args.supported, args.unsupported]
versions = [args.all, args.devel, args.lts, args.stable, args.supported, args.unsupported]
if len([x for x in versions if x]) != 1:
parser.error("You have to select exactly one of --all, --devel, --lts, "
"--stable, --supported, --unsupported.")
parser.error(
"You have to select exactly one of --all, --devel, --lts, "
"--stable, --supported, --unsupported."
)
if args.date is not None:
try:
args.date = convert_date(args.date)
except ValueError:
parser.error("Option --date needs to be a date in ISO 8601 "
"format.")
parser.error("Option --date needs to be a date in ISO 8601 format.")
return args
def main():
def main() -> None:
args = parse_args()
if args.all:
for distro in UbuntuDistroInfo().all:

View File

@ -3,10 +3,10 @@ VENDOR ?= $(shell dpkg-vendor --query Vendor | tr '[:upper:]' '[:lower:]')
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

View File

@ -17,7 +17,7 @@ set -f
# 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 @@ Options:
--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
-s --stable latest stable version
--supported list of all supported stable versions
-t --testing current testing version
-s --stable latest stable version
-o --oldstable latest oldstable version
--supported list of all supported versions (including development)
-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 @@ cb_testing() {
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 "$@"

View File

@ -25,7 +25,14 @@ store() {
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 @@ restore() {
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 @@ devel() {
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 @@ cb_stable() {
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 @@ filter_data() {
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 @@ main() {
-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 @@ main() {
-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";;

View File

@ -17,27 +17,29 @@ set -f
# 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 versions (including development)
--supported-esm list of all Ubuntu Advantage 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 @@ cb_devel() {
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;

View File

@ -26,6 +26,14 @@ runCommand() {
assertEquals "return value of ${COMMAND} $param\n" $exp_retval $retval
}
hasWarning() {
local param="$1"
local exp_stderr="$2"
local stderrF="${SHUNIT_TMPDIR}/stderr"
eval "${COMMAND} $param" > /dev/null 2> ${stderrF}
assertEquals "error output of ${COMMAND} $param\n" "$exp_stderr" "$(cat ${stderrF})"
}
success() {
runCommand "$1" "$2" "" 0
}

View File

@ -69,6 +69,14 @@ experimental"
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 @@ Options:
--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
-s --stable latest stable version
--supported list of all supported stable versions
-t --testing current testing version
-s --stable latest stable version
-o --oldstable latest oldstable version
--supported list of all supported versions (including development)
-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 @@ See debian-distro-info(1) for more info.'
}
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 @@ testExactlyOne() {
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() {
@ -240,6 +250,11 @@ testUnknownSeries() {
failure "--series foobar" "debian-distro-info: unknown distribution series \`foobar'"
}
testSourceDateEpoch() {
SOURCE_DATE_EPOCH=1675417275 success "--stable" "bullseye"
SOURCE_DATE_EPOCH=badcoffee hasWarning "--stable" "debian-distro-info: Environment variable SOURCE_DATE_EPOCH='badcoffee' not a valid epoch. Ignoring."
}
testDays() {
# day after lenny released
date=2009-02-15
@ -315,6 +330,41 @@ testDays() {
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" "1088"
success "--testing --date=$date --days=eol -c" "wheezy 1088"
success "--testing --date=$date --days=eol -f" "Debian 7 \"Wheezy\" 1088"
success "--testing --date=$date --days=eol -r" "7 1088"
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

View File

@ -117,9 +117,9 @@ testFullname() {
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 @@ testRelease() {
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"
}
@ -174,9 +174,9 @@ Options:
--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
--supported list of all supported stable versions
--lts latest long term support (LTS) version
--supported list of all supported versions (including development)
--supported-esm list of all Ubuntu Advantage supported stable versions
--unsupported list of all unsupported stable versions
-c --codename print the codename (default)
@ -246,6 +246,11 @@ testUnknownSeries() {
failure "--series foobar" "ubuntu-distro-info: unknown distribution series \`foobar'"
}
testSourceDateEpoch() {
SOURCE_DATE_EPOCH=1664860020 success "--stable" "jammy"
SOURCE_DATE_EPOCH=chocolate hasWarning "--stable" "ubuntu-distro-info: Environment variable SOURCE_DATE_EPOCH='chocolate' not a valid epoch. Ignoring."
}
testDays() {
# day after lucid released
date=2010-04-30
@ -272,10 +277,10 @@ testDays() {
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
@ -297,15 +302,15 @@ testDays() {
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" "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" "1826"
success "--date=$date --lts --days=eol-server -c" "precise 1826"
success "--date=$date --lts --days=eol-server -f" "Ubuntu 12.04 LTS \"Precise Pangolin\" 1826"
success "--date=$date --lts --days=eol-server -r" "12.04 LTS 1826"
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