Skip to content
Snippets Groups Projects
Unverified Commit 974fa7b2 authored by Gabriel-Ladzaretti's avatar Gabriel-Ladzaretti Committed by GitHub
Browse files

refactor(versioning/distro-info): for future use in debian and ubuntu versioning (#14880)

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

distro-info refactor

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

styling

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

distro-info refactor

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

styling

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

use https://debian.pages.debian.net/distro-info-data/ubuntu.csv

 as distro info data

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

cr changes and migrated from mjs to ts

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

added a crude way to prevent writing corrupted data

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

lint fixes

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

cr changes and migrated from mjs to ts

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

cr changes

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

dynamically check if stable/released.

22.04 release for example

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

fixed JSON order

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

removed ts.ignore

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

cr changes

* refactor(tools/distro-info): for later use in ubuntu and debian versioning

cr changes

Co-authored-by: default avatarMichael Kriese <michael.kriese@visualon.de>
parent 0ffab682
Branches
Tags
No related merge requests found
{ {
"4.10": "warty", "v4.10": {
"5.04": "hoary", "codename": "Warty Warthog",
"5.10": "breezy", "series": "warty",
"6.06": "dapper", "created": "2004-03-05",
"6.10": "edgy", "release": "2004-10-20",
"7.04": "feisty", "eol": "2006-04-30"
"7.10": "gutsy", },
"8.04": "hardy", "v5.04": {
"8.10": "intrepid", "codename": "Hoary Hedgehog",
"9.04": "jaunty", "series": "hoary",
"9.10": "karmic", "created": "2004-10-20",
"10.04": "lucid", "release": "2005-04-08",
"10.10": "maverick", "eol": "2006-10-31"
"11.04": "natty", },
"11.10": "oneiric", "v5.10": {
"12.04": "precise", "codename": "Breezy Badger",
"12.10": "quantal", "series": "breezy",
"13.04": "raring", "created": "2005-04-08",
"13.10": "saucy", "release": "2005-10-12",
"14.04": "trusty", "eol": "2007-04-13"
"14.10": "utopic", },
"15.04": "vivid", "v6.06": {
"15.10": "wily", "codename": "Dapper Drake",
"16.04": "xenial", "series": "dapper",
"16.10": "yakkety", "created": "2005-10-12",
"17.04": "zesty", "release": "2006-06-01",
"17.10": "artful", "eol": "2009-07-14",
"18.04": "bionic", "eol_server": "2011-06-01"
"18.10": "cosmic", },
"19.04": "disco", "v6.10": {
"19.10": "eoan", "codename": "Edgy Eft",
"20.04": "focal", "series": "edgy",
"20.10": "groovy", "created": "2006-06-01",
"21.04": "hirsute", "release": "2006-10-26",
"21.10": "impish", "eol": "2008-04-26"
"22.04": "jammy" },
"v7.04": {
"codename": "Feisty Fawn",
"series": "feisty",
"created": "2006-10-26",
"release": "2007-04-19",
"eol": "2008-10-19"
},
"v7.10": {
"codename": "Gutsy Gibbon",
"series": "gutsy",
"created": "2007-04-19",
"release": "2007-10-18",
"eol": "2009-04-18"
},
"v8.04": {
"codename": "Hardy Heron",
"series": "hardy",
"created": "2007-10-18",
"release": "2008-04-24",
"eol": "2011-05-12",
"eol_server": "2013-05-09"
},
"v8.10": {
"codename": "Intrepid Ibex",
"series": "intrepid",
"created": "2008-04-24",
"release": "2008-10-30",
"eol": "2010-04-30"
},
"v9.04": {
"codename": "Jaunty Jackalope",
"series": "jaunty",
"created": "2008-10-30",
"release": "2009-04-23",
"eol": "2010-10-23"
},
"v9.10": {
"codename": "Karmic Koala",
"series": "karmic",
"created": "2009-04-23",
"release": "2009-10-29",
"eol": "2011-04-30"
},
"v10.04": {
"codename": "Lucid Lynx",
"series": "lucid",
"created": "2009-10-29",
"release": "2010-04-29",
"eol": "2013-05-09",
"eol_server": "2015-04-30"
},
"v10.10": {
"codename": "Maverick Meerkat",
"series": "maverick",
"created": "2010-04-29",
"release": "2010-10-10",
"eol": "2012-04-10"
},
"v11.04": {
"codename": "Natty Narwhal",
"series": "natty",
"created": "2010-10-10",
"release": "2011-04-28",
"eol": "2012-10-28"
},
"v11.10": {
"codename": "Oneiric Ocelot",
"series": "oneiric",
"created": "2011-04-28",
"release": "2011-10-13",
"eol": "2013-05-09"
},
"v12.04": {
"codename": "Precise Pangolin",
"series": "precise",
"created": "2011-10-13",
"release": "2012-04-26",
"eol": "2017-04-28",
"eol_server": "2017-04-28",
"eol_esm": "2019-04-28"
},
"v12.10": {
"codename": "Quantal Quetzal",
"series": "quantal",
"created": "2012-04-26",
"release": "2012-10-18",
"eol": "2014-05-16"
},
"v13.04": {
"codename": "Raring Ringtail",
"series": "raring",
"created": "2012-10-18",
"release": "2013-04-25",
"eol": "2014-01-27"
},
"v13.10": {
"codename": "Saucy Salamander",
"series": "saucy",
"created": "2013-04-25",
"release": "2013-10-17",
"eol": "2014-07-17"
},
"v14.04": {
"codename": "Trusty Tahr",
"series": "trusty",
"created": "2013-10-17",
"release": "2014-04-17",
"eol": "2019-04-25",
"eol_server": "2019-04-25",
"eol_esm": "2024-04-25"
},
"v14.10": {
"codename": "Utopic Unicorn",
"series": "utopic",
"created": "2014-04-17",
"release": "2014-10-23",
"eol": "2015-07-23"
},
"v15.04": {
"codename": "Vivid Vervet",
"series": "vivid",
"created": "2014-10-23",
"release": "2015-04-23",
"eol": "2016-02-04"
},
"v15.10": {
"codename": "Wily Werewolf",
"series": "wily",
"created": "2015-04-23",
"release": "2015-10-22",
"eol": "2016-07-28"
},
"v16.04": {
"codename": "Xenial Xerus",
"series": "xenial",
"created": "2015-10-22",
"release": "2016-04-21",
"eol": "2021-04-21",
"eol_server": "2021-04-21",
"eol_esm": "2026-04-23"
},
"v16.10": {
"codename": "Yakkety Yak",
"series": "yakkety",
"created": "2016-04-21",
"release": "2016-10-13",
"eol": "2017-07-20"
},
"v17.04": {
"codename": "Zesty Zapus",
"series": "zesty",
"created": "2016-10-13",
"release": "2017-04-13",
"eol": "2018-01-13"
},
"v17.10": {
"codename": "Artful Aardvark",
"series": "artful",
"created": "2017-04-13",
"release": "2017-10-19",
"eol": "2018-07-19"
},
"v18.04": {
"codename": "Bionic Beaver",
"series": "bionic",
"created": "2017-10-19",
"release": "2018-04-26",
"eol": "2023-04-26",
"eol_server": "2023-04-26",
"eol_esm": "2028-04-26"
},
"v18.10": {
"codename": "Cosmic Cuttlefish",
"series": "cosmic",
"created": "2018-04-26",
"release": "2018-10-18",
"eol": "2019-07-18"
},
"v19.04": {
"codename": "Disco Dingo",
"series": "disco",
"created": "2018-10-18",
"release": "2019-04-18",
"eol": "2020-01-23"
},
"v19.10": {
"codename": "Eoan Ermine",
"series": "eoan",
"created": "2019-04-18",
"release": "2019-10-17",
"eol": "2020-07-17"
},
"v20.04": {
"codename": "Focal Fossa",
"series": "focal",
"created": "2019-10-17",
"release": "2020-04-23",
"eol": "2025-04-23",
"eol_server": "2025-04-23",
"eol_esm": "2030-04-23"
},
"v20.10": {
"codename": "Groovy Gorilla",
"series": "groovy",
"created": "2020-04-23",
"release": "2020-10-22",
"eol": "2021-07-22"
},
"v21.04": {
"codename": "Hirsute Hippo",
"series": "hirsute",
"created": "2020-10-22",
"release": "2021-04-22",
"eol": "2022-01-20"
},
"v21.10": {
"codename": "Impish Indri",
"series": "impish",
"created": "2021-04-22",
"release": "2021-10-14",
"eol": "2022-07-14"
},
"v22.04": {
"codename": "Jammy Jellyfish",
"series": "jammy",
"created": "2021-10-14",
"release": "2022-04-21",
"eol": "2027-04-21",
"eol_server": "2027-04-21",
"eol_esm": "2032-04-21"
}
} }
import dataFiles, { DataFile } from '../../data-files.generated';
interface DistroSchedule {
codename: string;
series: string;
created: string;
release: string;
eol: string;
eol_server?: string;
eol_esm?: string;
eol_lts?: string;
eol_elts?: string;
}
type DistroDataFile = 'data/ubuntu-distro-info.json';
export type DistroInfoRecord = Record<string, DistroSchedule>;
export type DistroInfoRecordWithVersion = { version: string } & DistroSchedule;
export class DistroInfo {
private readonly _codenameToVersion = new Map<
string,
DistroInfoRecordWithVersion
>();
private readonly _distroInfo: DistroInfoRecord;
constructor(distroJsonKey: DistroDataFile) {
this._distroInfo = JSON.parse(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
dataFiles.get(distroJsonKey as DataFile)!.replace(/v([\d.]+)\b/gm, '$1')
);
for (const version of Object.keys(this._distroInfo)) {
const schedule = this._distroInfo[version];
this._codenameToVersion.set(schedule.series, { version, ...schedule });
}
}
public isCodename(input: string): boolean {
return this._codenameToVersion.has(input);
}
public getVersionByCodename(input: string): string {
const schedule = this._codenameToVersion.get(input);
if (schedule) {
return schedule.version;
}
return input;
}
public getCodenameByVersion(input: string): string {
const di = this._distroInfo[input];
if (di) {
return di.series;
}
// istanbul ignore next
return input;
}
public getSchedule(input: string): DistroSchedule {
return this._distroInfo[input];
}
}
import dataFiles from '../../../data-files.generated';
export type UbuntuDistroInfo = Record<string, string>;
// Data file generated with:
// distro-json-generate.mjs
const ubuntuJsonKey = 'data/ubuntu-distro-info.json';
const ubuntuDistroInfo: UbuntuDistroInfo = JSON.parse(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
dataFiles.get(ubuntuJsonKey)!
);
const codenameToVersion = new Map<string, string>();
for (const version of Object.keys(ubuntuDistroInfo)) {
const codename = ubuntuDistroInfo[version];
codenameToVersion.set(codename, version);
}
export function isCodename(input: string): boolean {
return codenameToVersion.has(input);
}
export function getVersionByCodename(input: string): string {
const ver = codenameToVersion.get(input);
if (ver) {
return ver;
}
return input;
}
export function getCodenameByVersion(input: string): string {
const codename = ubuntuDistroInfo[input];
if (codename) {
return codename;
}
// istanbul ignore next
return input;
}
import { DateTime } from 'luxon';
import { regEx } from '../../../util/regex'; import { regEx } from '../../../util/regex';
import { DistroInfo } from '../distro';
import type { NewValueConfig, VersioningApi } from '../types'; import type { NewValueConfig, VersioningApi } from '../types';
import {
getCodenameByVersion,
getVersionByCodename,
isCodename,
} from './distribution';
export const id = 'ubuntu'; export const id = 'ubuntu';
export const displayName = 'Ubuntu'; export const displayName = 'Ubuntu';
export const urls = ['https://changelogs.ubuntu.com/meta-release']; export const urls = [
'https://changelogs.ubuntu.com/meta-release',
'https://debian.pages.debian.net/distro-info-data/ubuntu.csv',
];
export const supportsRanges = false; export const supportsRanges = false;
// #12509 const di = new DistroInfo('data/ubuntu-distro-info.json');
const temporarilyUnstable = ['22.04'];
// validation // validation
...@@ -22,7 +21,7 @@ function isValid(input: string): boolean { ...@@ -22,7 +21,7 @@ function isValid(input: string): boolean {
regEx(/^(0[4-5]|[6-9]|[1-9][0-9])\.[0-9][0-9](\.[0-9]{1,2})?$/).test( regEx(/^(0[4-5]|[6-9]|[1-9][0-9])\.[0-9][0-9](\.[0-9]{1,2})?$/).test(
input input
)) || )) ||
isCodename(input) di.isCodename(input)
); );
} }
...@@ -39,20 +38,23 @@ function isSingleVersion(version: string): boolean { ...@@ -39,20 +38,23 @@ function isSingleVersion(version: string): boolean {
} }
function isStable(version: string): boolean { function isStable(version: string): boolean {
const ver = getVersionByCodename(version); const ver = di.getVersionByCodename(version);
if (!isValid(ver)) { if (!isValid(ver)) {
return false; return false;
} }
if (temporarilyUnstable.includes(ver)) {
const schedule = di.getSchedule(ver);
if (schedule && DateTime.fromISO(schedule.release) > DateTime.now()) {
return false; return false;
} }
return regEx(/^\d?[02468]\.04/).test(ver); return regEx(/^\d?[02468]\.04/).test(ver);
} }
// digestion of version // digestion of version
function getMajor(version: string): null | number { function getMajor(version: string): null | number {
const ver = getVersionByCodename(version); const ver = di.getVersionByCodename(version);
if (isValid(ver)) { if (isValid(ver)) {
const [major] = ver.split('.'); const [major] = ver.split('.');
return parseInt(major, 10); return parseInt(major, 10);
...@@ -61,7 +63,7 @@ function getMajor(version: string): null | number { ...@@ -61,7 +63,7 @@ function getMajor(version: string): null | number {
} }
function getMinor(version: string): null | number { function getMinor(version: string): null | number {
const ver = getVersionByCodename(version); const ver = di.getVersionByCodename(version);
if (isValid(ver)) { if (isValid(ver)) {
const [, minor] = ver.split('.'); const [, minor] = ver.split('.');
return parseInt(minor, 10); return parseInt(minor, 10);
...@@ -70,7 +72,7 @@ function getMinor(version: string): null | number { ...@@ -70,7 +72,7 @@ function getMinor(version: string): null | number {
} }
function getPatch(version: string): null | number { function getPatch(version: string): null | number {
const ver = getVersionByCodename(version); const ver = di.getVersionByCodename(version);
if (isValid(ver)) { if (isValid(ver)) {
const [, , patch] = ver.split('.'); const [, , patch] = ver.split('.');
return patch ? parseInt(patch, 10) : null; return patch ? parseInt(patch, 10) : null;
...@@ -81,8 +83,8 @@ function getPatch(version: string): null | number { ...@@ -81,8 +83,8 @@ function getPatch(version: string): null | number {
// comparison // comparison
function equals(version: string, other: string): boolean { function equals(version: string, other: string): boolean {
const ver = getVersionByCodename(version); const ver = di.getVersionByCodename(version);
const otherVer = getVersionByCodename(other); const otherVer = di.getVersionByCodename(other);
return isVersion(ver) && isVersion(otherVer) && ver === otherVer; return isVersion(ver) && isVersion(otherVer) && ver === otherVer;
} }
...@@ -130,10 +132,10 @@ function getNewValue({ ...@@ -130,10 +132,10 @@ function getNewValue({
currentVersion, currentVersion,
newVersion, newVersion,
}: NewValueConfig): string { }: NewValueConfig): string {
if (isCodename(currentValue)) { if (di.isCodename(currentValue)) {
return getCodenameByVersion(newVersion); return di.getCodenameByVersion(newVersion);
} }
return getVersionByCodename(newVersion); return di.getVersionByCodename(newVersion);
} }
function sortVersions(version: string, other: string): number { function sortVersions(version: string, other: string): number {
......
import fs from 'fs-extra'; import fs from 'fs-extra';
import got from 'got';
import shell from 'shelljs'; import shell from 'shelljs';
shell.echo(`Verifying required packages...`); const url = 'https://debian.pages.debian.net/distro-info-data/ubuntu.csv';
if (!shell.which(`distro-info`)) { /**
shell.echo('This script requires distro-info, exiting...'); * Converts valid CSV string into JSON.
shell.exit(2); * @param {string} raw CSV string
} * @returns {string} JSON representation of input CSV
*/
function csvToJson(raw) {
const lines = raw.split(/\r?\n/);
if (!shell.which(`sed`)) { /** @type {Record<string, any>} */
shell.echo('This script requires sed, exiting...'); const res = {};
shell.exit(2); const headers = lines[0].split(',');
}
shell.echo(`OK`); // drop headers
lines.shift();
const ubuntuDistroInfo = shell.exec( // drop "version" header
`ubuntu-distro-info --all -f | sed -r 's/Ubuntu|"|LTS |Debian //g; s/([0-9]+.[0-9]+) /\\1 /; s/.*/\\L&/; s/( [a-z]*) [a-z]*/\\1/g; s/^[ \\t]*//'`, headers.shift();
{ silent: true }
);
/** for (const l of lines) {
* @param {string} str if (!l) {
* @returns {{}} continue;
*/ }
function objectify(str) {
let obj = {};
for (const line of str.split(/\r?\n/)) { /** @type {Record<string, any>} */
let [ver, codename] = line.split(' '); const obj = {};
// eslint-disable-next-line const line = l.split(',');
// @ts-ignore let ver = line?.shift()?.replace(/LTS|\s/g, '');
obj[ver] = codename;
} for (const [i, h] of headers.entries()) {
obj[h.replace('-', '_')] = line[i];
}
return obj; if (ver) {
// Debian related, example codename "hamm" version is 2.0
// change 2.0 -> 2
ver = ver.endsWith('.0') ? ver.replace('.0', '') : ver;
res[`v${ver}`] = obj;
}
}
return JSON.stringify(res, undefined, 2);
} }
/** /**
* @param {string} file * Update given file with new provided data.
* @param {string} newData * @param {string} file Path to a data file
* @param {string} newData New data to be written
*/ */
async function updateJsonFile(file, newData) { async function updateJsonFile(file, newData) {
let oldData;
try {
oldData = fs.existsSync(file) ? await fs.readFile(file, 'utf8') : null;
// Eliminate formatting
oldData = oldData?.replace(/\s/g, '') ?? null;
} catch (e) {
shell.echo(e.toString());
shell.exit(1);
}
const parsedData = JSON.stringify(objectify(newData), undefined, 2);
if (oldData === parsedData) {
shell.echo(`${file} is up to date.`);
return;
}
try { try {
shell.echo(`Updating ${file}`); shell.echo(`Updating ${file}`);
await fs.writeFile(file, parsedData); await fs.writeFile(file, newData);
} catch (e) { } catch (e) {
shell.echo(e.toString()); shell.echo(e.toString());
shell.exit(1); shell.exit(1);
} }
} }
/**
* Fetch CSV and update data file.
* @param {string} url Url to CSV
* @param {string} file File path to update
*/
async function update(url, file) {
const res = await got(url);
const csv = res.body;
const json = csvToJson(csv);
await updateJsonFile(file, json);
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises // eslint-disable-next-line @typescript-eslint/no-floating-promises
updateJsonFile(`../data/ubuntu-distro-info.json`, ubuntuDistroInfo.toString()); update(url, `./data/ubuntu-distro-info.json`);
...@@ -131,7 +131,7 @@ async function generateData() { ...@@ -131,7 +131,7 @@ async function generateData() {
await updateFile( await updateFile(
`lib/data-files.generated.ts`, `lib/data-files.generated.ts`,
[ [
`type DataFile =\n${importDataFileType};`, `export type DataFile =\n${importDataFileType};`,
contentMapDecl, contentMapDecl,
contentMapAssignments.join('\n'), contentMapAssignments.join('\n'),
`export default data;\n`, `export default data;\n`,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment