country.pl: generate final structure as json at build time directly

Currently, we generate a custom-format `country.dat` at build time,
which we then ship with the installer. In the live environment, this
then gets parsed (via regexes) into another format and is finally
written out as JSON for e.g. the TUI and auto-installer to consume.

Instead, skip the intermediate format completely and just generate the
final data structure as JSON at build time.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
This commit is contained in:
Christoph Heiss 2024-12-09 13:45:55 +01:00 committed by Thomas Lamprecht
parent 18a1b8c20d
commit dc401eb3f0
5 changed files with 113 additions and 89 deletions

2
.gitignore vendored
View File

@ -8,4 +8,4 @@
/test*.img
/testdir/
Cargo.lock
country.dat
locale-info.json

View File

@ -19,7 +19,7 @@ else
CARGO_COMPILEDIR := target/debug
endif
INSTALLER_SOURCES=$(shell git ls-files) country.dat
INSTALLER_SOURCES=$(shell git ls-files) locale-info.json
PREFIX = /usr
BINDIR = $(PREFIX)/bin
@ -72,9 +72,9 @@ $(BUILDDIR):
cp -a debian $@.tmp/
mv $@.tmp $@
country.dat: country.pl
./country.pl > country.dat.tmp
mv country.dat.tmp country.dat
locale-info.json: country.pl
./country.pl > $@.tmp
mv $@.tmp $@
deb: $(DEB)
$(ASSISTANT_DEB): $(DEB)
@ -100,10 +100,10 @@ sbuild: $(DSC)
sbuild $(DSC)
.PHONY: prepare-test-env
prepare-test-env: cd-info.test country.dat test.img
prepare-test-env: cd-info.test locale-info.json test.img
rm -rf testdir
mkdir -p testdir/var/lib/proxmox-installer/
cp -v country.dat testdir/var/lib/proxmox-installer/
cp -v locale-info.json testdir/var/lib/proxmox-installer/
./proxmox-low-level-installer -t test.img dump-env
.PHONY: test
@ -124,7 +124,7 @@ install: $(INSTALLER_SOURCES) $(COMPILED_BINS)
install -D -m 644 interfaces $(DESTDIR)/etc/network/interfaces
install -D -m 755 fake-start-stop-daemon $(VARLIBDIR)/fake-start-stop-daemon
install -D -m 755 policy-disable-rc.d $(VARLIBDIR)/policy-disable-rc.d
install -D -m 644 country.dat $(VARLIBDIR)/country.dat
install -D -m 644 locale-info.json $(VARLIBDIR)/locale-info.json
install -D -m 755 unconfigured.sh $(DESTDIR)/sbin/unconfigured.sh
install -D -m 755 proxinstall $(DESTDIR)/usr/bin/proxinstall
install -D -m 755 proxmox-low-level-installer $(DESTDIR)/$(BINDIR)/proxmox-low-level-installer
@ -226,5 +226,5 @@ check-pbs-tui: prepare-check-pbs
clean:
rm -rf target build $(PACKAGE)-[0-9]* testdir
rm -f $(PACKAGE)*.tar* *.deb packages packages.tmp *.build *.dsc *.buildinfo *.changes
rm -f test*.img pve-final.pkglist country.dat final.pkglist cd-info.test
rm -f test*.img pve-final.pkglist locale-info.json final.pkglist cd-info.test
find . -name '*~' -exec rm {} ';'

View File

@ -5,6 +5,9 @@ use warnings;
use Carp;
use Cwd ();
use JSON qw(from_json);
use Proxmox::Sys::File qw(file_read_all);
use base qw(Exporter);
our @EXPORT = qw(is_test_mode);
@ -33,57 +36,8 @@ my $product_cfg = {
my sub read_locale_info {
my ($lib_dir) = @_;
my $countryfn = "${lib_dir}/country.dat";
open (my $COUNTRY_MAP_FH, "<:encoding(utf8)", "$countryfn") || die "unable to open '$countryfn' - $!\n";
my ($country, $countryhash, $kmap, $kmaphash) = ({}, {}, {}, {});
while (defined (my $line = <$COUNTRY_MAP_FH>)) {
if ($line =~ m|^map:([^\s:]+):([^:]+):([^:]+):([^:]+):([^:]+):([^:]*):$|) {
$kmap->{$1} = {
name => $2,
kvm => $3,
console => $4,
x11 => $5,
x11var => $6,
};
$kmaphash->{$2} = $1;
} elsif ($line =~ m|^([a-z]{2}):([^:]+):([^:]*):([^:]*):$|) {
$country->{$1} = {
name => $2,
kmap => $3,
mirror => $4,
};
$countryhash->{lc($2)} = $1;
} else {
warn "unable to parse 'country.dat' line: $line";
}
}
close ($COUNTRY_MAP_FH);
my $zonefn = "/usr/share/zoneinfo/zone.tab";
open (my $ZONE_TAB_FH, '<', "$zonefn") || die "unable to open '$zonefn' - $!\n";
my ($zones, $cczones) = ({}, {});
while (defined (my $line = <$ZONE_TAB_FH>)) {
next if $line =~ m/^\s*(?:#|$)/;
if ($line =~ m|^([A-Z][A-Z])\s+\S+\s+(([^/]+)/\S+)\s|) {
my $cc = lc($1);
$cczones->{$cc}->{$2} = 1;
$country->{$cc}->{zone} = $2 if !defined ($country->{$cc}->{zone});
$zones->{$2} = 1;
}
}
close ($ZONE_TAB_FH);
return {
zones => $zones,
cczones => $cczones,
country => $country,
countryhash => $countryhash,
kmap => $kmap,
kmaphash => $kmaphash,
}
my $json = file_read_all("${lib_dir}/locale-info.json");
return from_json($json, { utf8 => 1 });
}
my sub get_cd_info {

View File

@ -4,32 +4,93 @@ use strict;
use warnings;
use PVE::Tools;
use JSON;
use JSON qw(from_json to_json);
# Generates a
#
# - country code => name/kmap/mirror
# - name => country code
#
# mapping for each defined country
my sub generate_country_mappings {
my ($country_codes, $defmap, $mirrors) = @_;
my ($countries, $countryhash) = ({}, {});
foreach my $cc (sort keys %$country_codes) {
my $name = $country_codes->{$cc};
my $kmap = $defmap->{$cc} || '';
my $mirror = $mirrors->{$cc} || '';
$countries->{$cc} = {
name => $name,
kmap => $kmap,
mirror => $mirror,
};
$countryhash->{lc($name)} = $cc;
}
return ($countries, $countryhash);
}
# we need mappings for X11, console, and kvm vnc
# LC(-LC)? => [DESC, kvm, console, X11, X11variant]
my sub generate_keymaps {
my ($country_codes) = @_;
my ($kmap, $kmaphash) = ({}, {});
my $keymaps = PVE::Tools::kvmkeymaps();
foreach my $km (sort keys %$keymaps) {
my ($name, $kvm, $console, $x11, $x11var) = @{$keymaps->{$km}};
if ($km =~m/^([a-z][a-z])-([a-z][a-z])$/i) {
defined ($country_codes->{$2}) || die "undefined country code '$2'";
} else {
defined ($country_codes->{$km}) || die "undefined country code '$km'";
}
$x11var = '' if !defined ($x11var);
$kmap->{$km} = {
name => $name,
kvm => $kvm,
console => $console,
x11 => $x11,
x11var => $x11var,
};
$kmaphash->{$name} = $km;
}
return ($kmap, $kmaphash);
}
my sub parse_zoneinfo {
my ($countries) = @_;
my $zonefn = "/usr/share/zoneinfo/zone.tab";
open (my $ZONE_TAB_FH, '<', "$zonefn") || die "unable to open '$zonefn' - $!\n";
my ($zones, $cczones) = ({}, {});
while (defined (my $line = <$ZONE_TAB_FH>)) {
next if $line =~ m/^\s*(?:#|$)/;
if ($line =~ m|^([A-Z][A-Z])\s+\S+\s+(([^/]+)/\S+)\s|) {
my $cc = lc($1);
$cczones->{$cc}->{$2} = 1;
$countries->{$cc}->{zone} = $2 if !defined ($countries->{$cc}->{zone});
$zones->{$2} = 1;
}
}
close ($ZONE_TAB_FH);
return ($zones, $cczones);
}
# country codes from:
my $country_codes_file = "/usr/share/iso-codes/json/iso_3166-1.json";
my $iso_3166_codes = from_json(PVE::Tools::file_get_contents($country_codes_file, 64 * 1024));
my $country = { map { lc($_->{'alpha_2'}) => $_->{'common_name'} // $_->{'name'} } @{$iso_3166_codes->{'3166-1'}} };
# we need mappings for X11, console, and kvm vnc
# LC(-LC)? => [DESC, kvm, console, X11, X11variant]
my $keymaps = PVE::Tools::kvmkeymaps();
foreach my $km (sort keys %$keymaps) {
my ($desc, $kvm, $console, $x11, $x11var) = @{$keymaps->{$km}};
if ($km =~m/^([a-z][a-z])-([a-z][a-z])$/i) {
defined ($country->{$2}) || die "undefined country code '$2'";
} else {
defined ($country->{$km}) || die "undefined country code '$km'";
}
$x11var = '' if !defined ($x11var);
print "map:$km:$desc:$kvm:$console:$x11:$x11var:\n";
}
my $country_codes = { map { lc($_->{'alpha_2'}) => $_->{'common_name'} // $_->{'name'} } @{$iso_3166_codes->{'3166-1'}} };
my $defmap = {
'us' => 'en-us',
@ -37,7 +98,7 @@ my $defmap = {
'br' => 'pt-br',
'ca' => 'en-us',
'dk' => 'dk',
'nl' => 'en-us', # most Dutch people us US layout
'nl' => 'en-us', # most Dutch people use US layout
'fi' => 'fi',
'fr' => 'fr',
'de' => 'de',
@ -61,14 +122,23 @@ my $defmap = {
'li' => 'de-ch',
};
my $mirrors = PVE::Tools::debmirrors();
foreach my $cc (keys %$mirrors) {
die "undefined country code '$cc'" if !defined ($country->{$cc});
die "undefined country code '$cc'" if !defined ($country_codes->{$cc});
}
foreach my $cc (sort keys %$country) {
my $map = $defmap->{$cc} || '';
my $mir = $mirrors->{$cc} || '';
print "$cc:$country->{$cc}:$map:$mir:\n";
}
my ($countries, $countryhash) = generate_country_mappings($country_codes, $defmap, $mirrors);
my ($kmap, $kmaphash) = generate_keymaps($country_codes);
my ($zones, $cczones) = parse_zoneinfo($countries);
my $locale_info = {
country => $countries,
countryhash => $countryhash,
kmap => $kmap,
kmaphash => $kmaphash,
zones => $zones,
cczones => $cczones,
};
my $json = to_json($locale_info, { utf8 => 1, canonical => 1 });
print $json;

View File

@ -1 +1 @@
{"iso-info":{"isoname":"proxmox-ve","isorelease":"2","product":"pve","productlong":"Proxmox VE","release":"8.0"},"locations":{"iso":"/cdrom","lib":"/var/lib/proxmox-installer","pkg":"/cdrom/proxmox/packages/","run":"/run/proxmox-installer"},"product":"pve","product-cfg":{"bridged_network":1,"enable_btrfs":1,"fullname":"Proxmox VE","port":"8006","product":"pve"},"run-env-cache-file":"/run/proxmox-installer/run-env-info.json"}
{"iso-info":{"isoname":"proxmox-ve","isorelease":"2","product":"pve","productlong":"Proxmox VE","release":"8.0"},"locations":{"iso":"../testdir","lib":"../testdir/var/lib/proxmox-installer","pkg":"../testdir/cdrom/proxmox/packages/","run":"../testdir/run/proxmox-installer"},"product":"pve","product-cfg":{"bridged_network":1,"enable_btrfs":1,"fullname":"Proxmox VE","port":"8006","product":"pve"},"run-env-cache-file":"testdir/run/proxmox-installer/run-env-info.json"}