@ -1,6 +1,6 @@
#!/usr/bin/env python3
#!/usr/bin/env python3
# Copyright (C) 2018 Simon Quigley <tsimonq2@ubuntu.com>
# Copyright (C) 2018 -2023 Simon Quigley <tsimonq2@ubuntu.com>
#
#
# This program is free software: you can redistribute it and/or modify
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# it under the terms of the GNU General Public License as published by
@ -19,152 +19,97 @@ import json
import libcalamares
import libcalamares
from time import strftime
from time import strftime
import urllib . request
import urllib . request
from urllib . error import HTTPError
from urllib . error import HTTPError , URLError
from urllib . error import URLError
import socket
import socket
import logging
import logging
import distro
import distro
import xml . etree . ElementTree as ET
import xml . etree . ElementTree as ET
from os import remove
global sources
sources = """ # Automatically generated by Calamares on DATE.
# Lines starting with "deb" are mandatory, while lines starting with "deb-src"
# are for more detailed package information.
## See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
## newer versions of DISTRIBUTION.
deb URL / ubuntu / CODENAME main restricted
# deb-src URL/ubuntu/ CODENAME main restricted
## Major bug fix updates produced after the final release of DISTRIBUTION.
## Have you noticed a regression? Please report it!
## https://wiki.ubuntu.com/StableReleaseUpdates#Regressions
deb URL / ubuntu / CODENAME - updates main restricted
# deb-src URL/ubuntu/ CODENAME-updates main restricted
## Software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu team.
## Also, please note that software in Universe WILL NOT receive any review or
## updates from the Ubuntu security team directly. Updates in this repository
## are provided by volunteers, but most come from Debian.
deb URL / ubuntu / CODENAME universe
# deb-src URL/ubuntu/ CODENAME universe
deb URL / ubuntu / CODENAME - updates universe
# deb-src URL/ubuntu/ CODENAME-updates universe
## Software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu team,
## and may not be under a free licence. Please satisfy yourself as your rights
## to use the software. Also, please note that software in Multiverse WILL NOT
## receive any review or updates from the Ubuntu security team directly.
deb URL / ubuntu / CODENAME multiverse
# deb-src URL/ubuntu/ CODENAME multiverse
deb URL / ubuntu / CODENAME - updates multiverse
# deb-src URL/ubuntu/ CODENAME-updates multiverse
## Software from this repository contains tested security updates from the
## Ubuntu security team.
deb http : / / security . ubuntu . com / ubuntu CODENAME - security main restricted
# deb-src http://security.ubuntu.com/ubuntu CODENAME-security main restricted
deb http : / / security . ubuntu . com / ubuntu CODENAME - security universe
# deb-src http://security.ubuntu.com/ubuntu CODENAME-security universe
deb http : / / security . ubuntu . com / ubuntu CODENAME - security multiverse
# deb-src http://security.ubuntu.com/ubuntu CODENAME-security multiverse
## Software from this repository may not have been tested as extensively as
## software contained in the main release, although it includes newer versions
## of some applications which may provide useful features. Also, please note
## that software in Backports WILL NOT receive any review or updates from the
## Ubuntu security team.
deb URL / ubuntu / CODENAME - backports main restricted universe multiverse
# deb-src URL/ubuntu/ CODENAME-backports main restricted universe multiverse"""
SUBDOMAINS_BY_COUNTRY_CODE = { " US " : " us. " ,
" AU " : " au. " ,
" SE " : " no. " ,
" NO " : " no. " ,
" NZ " : " nz. " ,
" NL " : " nl. " ,
" KR " : " kr. " ,
" DE " : " de. " ,
" GE " : " ge. " ,
" PF " : " pf. " ,
" CZ " : " cz. " ,
" HR " : " hr. " }
def getcountrycode ( ) :
"""
Return the two - letter country code or an empty string .
Tries to determine the country code based on the public IP address ,
if the device is connected to the Internet . Otherwise it returns
an empty string .
"""
if libcalamares . globalstorage . value ( " hasInternet " ) :
geoip_style = libcalamares . job . configuration [ " geoip " ] [ " style " ]
geoipurl = libcalamares . job . configuration [ " geoip " ] [ " url " ]
try :
SUBDOMAINS_BY_COUNTRY_CODE = {
with urllib . request . urlopen ( geoipurl , timeout = 75 ) as http_response :
" US " : " us. " , " AU " : " au. " , " SE " : " no. " , " NO " : " no. " ,
if geoip_style == " json " :
" NZ " : " nz. " , " NL " : " nl. " , " KR " : " kr. " , " DE " : " de. " ,
localedata = json . loads ( http_response . read ( ) . decode ( ) )
" GE " : " ge. " , " PF " : " pf. " , " CZ " : " cz. " , " HR " : " hr. "
return localedata [ " country_code " ]
}
elif geoip_style == " xml " :
tree = ET . parse ( http_response )
root = tree . getroot ( )
def get_sources_template ( ) :
return root . find ( " CountryCode " ) . text
return """ # Automatically generated by Calamares on {date} .
else :
# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
logging . error ( " Unknown geoip style: %s " , geoip_style )
# newer versions of {distro}.
except HTTPError as http_error :
logging . error ( " Data not retrieved because %s - URL: %s " ,
Types : deb
http_error , geoipurl )
URIs : { url }
except URLError as url_error :
Suites : { codename } { codename } - updates
if isinstance ( url_error . reason , socket . timeout ) :
Components : main universe
logging . error ( " Socket timed out - URL %s " , geoipurl )
Signed - By : / usr / share / keyrings / ubuntu - archive - keyring . gpg
else :
"""
logging . error ( " Non-timeout protocol error. " )
else :
logging . info ( " Country successfully determined. " )
def get_sec_sources_template ( ) :
return " "
return """ Types: deb
URIs : http : / / security . ubuntu . com / ubuntu
Suites : { codename } - security
Components : main universe
Signed - By : / usr / share / keyrings / ubuntu - archive - keyring . gpg
"""
def get_restricted_sources_template ( ) :
return """ Types: deb
URIs : { url }
Suites : { codename } { codename } - updates
Components : restricted multiverse
Signed - By : / usr / share / keyrings / ubuntu - archive - keyring . gpg
Enabled : no
"""
def get_subdomain_by_country ( countrycode ) :
""" Return the subdomain for the given countrycode
def get_country_code ( ) :
or an empty string .
if not libcalamares . globalstorage . value ( " hasInternet " ) :
"""
if countrycode in SUBDOMAINS_BY_COUNTRY_CODE . keys ( ) :
return SUBDOMAINS_BY_COUNTRY_CODE [ countrycode ]
else :
return " "
return " "
geoip_config = libcalamares . job . configuration [ " geoip " ]
def getcodename ( ) :
try :
""" Return the codename of the distribution, similar to lsb_release -cs """
with urllib . request . urlopen ( geoip_config [ " url " ] , timeout = 75 ) as resp :
return distro . codename ( )
if geoip_config [ " style " ] == " json " :
return json . loads ( resp . read ( ) . decode ( ) ) [ " country_code " ]
elif geoip_config [ " style " ] == " xml " :
return ET . parse ( resp ) . getroot ( ) . find ( " CountryCode " ) . text
except ( HTTPError , URLError , socket . timeout ) :
logging . error ( " Failed to get country code. " )
return " "
def changesources ( subdomain ) :
def get_subdomain_by_country ( country_code ) :
""" Replace the placeholders and then create the sources.list """
return SUBDOMAINS_BY_COUNTRY_CODE . get ( country_code , " " )
distro = libcalamares . job . configuration [ " distribution " ]
url = " http:// {} {} " . format ( subdomain ,
libcalamares . job . configuration [ " baseUrl " ] )
global sources
sources = sources . replace ( " DISTRIBUTION " , distro )
sources = sources . replace ( " CODENAME " , getcodename ( ) )
sources = sources . replace ( " URL " , url )
sources = sources . replace ( " DATE " , strftime ( " % Y- % m- %d " ) )
filepath = libcalamares . globalstorage . value ( " rootMountPoint " )
def write_file ( path , content ) :
filepath + = " /etc/apt/sources.list "
with open ( path , " w " ) as f :
with open ( filepath , " r+ " ) as sourcesfile :
f . write ( content )
sourcesfile . seek ( 0 )
sourcesfile . write ( sources )
sourcesfile . truncate ( )
def run ( ) :
def run ( ) :
""" Autoselect a mirror and create the sources.list file. """
country_code = get_country_code ( )
countrycode = getcountrycode ( )
subdomain = get_subdomain_by_country ( country_code )
subdomain = get_subdomain_by_country ( countrycode )
base_url = " http:// {} {} /ubuntu " . format ( subdomain , libcalamares . job . configuration [ " baseUrl " ] )
codename = distro . codename ( )
root_mount_point = libcalamares . globalstorage . value ( " rootMountPoint " )
sources = get_sources_template ( ) . format ( date = strftime ( " % Y- % m- %d " ) , distro = libcalamares . job . configuration [ " distribution " ] , url = base_url , codename = codename )
write_file ( f " { root_mount_point } /etc/apt/sources.list.d/ubuntu.sources " , sources )
sec_sources = get_sec_sources_template ( ) . format ( codename = codename )
write_file ( f " { root_mount_point } /etc/apt/sources.list.d/ubuntu_security.sources " , sec_sources )
restricted_sources = get_restricted_sources_template ( ) . format ( url = base_url , codename = codename )
write_file ( f " { root_mount_point } /etc/apt/sources.list.d/ubuntu_nonfree.sources " , restricted_sources )
remove ( f " { root_mount_point } /etc/apt/sources.list " )
changesources ( subdomain )
libcalamares . globalstorage . insert ( " mirrorURL " , base_url )
libcalamares . globalstorage . insert ( " ubuntuCodename " , codename )