Skip to content

Commit

Permalink
Resolved a merge conflict, and tweaked local mirror listing to match …
Browse files Browse the repository at this point in the history
…that of remote mirror-listing
  • Loading branch information
Torxed committed Nov 9, 2024
2 parents b2555c0 + de664df commit 065342c
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 42 deletions.
14 changes: 13 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,19 @@ repos:
'--config-file=pyproject.toml'
]
fail_fast: true
additional_dependencies:
- pydantic
- pydantic-settings
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.2
rev: v0.7.3
hooks:
- id: ruff
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
fail_fast: true
require_serial: true
5 changes: 5 additions & 0 deletions PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ depends=(
'python-simple-term-menu'
'systemd'
'util-linux'
'xfsprogs'
'lvm2'
'f2fs-tools'
'ntfs-3g'
'reiserfsprogs'
)
makedepends=(
'python-setuptools'
Expand Down
3 changes: 1 addition & 2 deletions archinstall/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,10 @@ def load_config() -> None:
arguments['audio_config'] = models.AudioConfiguration.parse_arg(arguments['audio_config'])

if arguments.get('disk_encryption', None) is not None and disk_config is not None:
password = arguments.get('encryption_password', '')
arguments['disk_encryption'] = disk.DiskEncryption.parse_arg(
arguments['disk_config'],
arguments['disk_encryption'],
password
arguments.get('encryption_password', '')
)


Expand Down
1 change: 1 addition & 0 deletions archinstall/default_profiles/desktops/i3.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def packages(self) -> list[str]:
'i3lock',
'i3status',
'i3blocks',
'xss-set',
'xterm',
'lightdm-gtk-greeter',
'lightdm',
Expand Down
13 changes: 8 additions & 5 deletions archinstall/lib/disk/device_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1232,32 +1232,35 @@ def validate_enc(cls, disk_config: DiskLayoutConfiguration) -> bool:
def parse_arg(
cls,
disk_config: DiskLayoutConfiguration,
arg: Dict[str, Any],
disk_encryption: Dict[str, Any],
password: str = ''
) -> Optional['DiskEncryption']:
if not cls.validate_enc(disk_config):
return None

if len(password) < 1:
return None

enc_partitions = []
for mod in disk_config.device_modifications:
for part in mod.partitions:
if part.obj_id in arg.get('partitions', []):
if part.obj_id in disk_encryption.get('partitions', []):
enc_partitions.append(part)

volumes = []
if disk_config.lvm_config:
for vol in disk_config.lvm_config.get_all_volumes():
if vol.obj_id in arg.get('lvm_volumes', []):
if vol.obj_id in disk_encryption.get('lvm_volumes', []):
volumes.append(vol)

enc = DiskEncryption(
EncryptionType(arg['encryption_type']),
EncryptionType(disk_encryption['encryption_type']),
password,
enc_partitions,
volumes
)

if hsm := arg.get('hsm_device', None):
if hsm := disk_encryption.get('hsm_device', None):
enc.hsm_device = Fido2Device.parse_arg(hsm)

return enc
Expand Down
94 changes: 69 additions & 25 deletions archinstall/lib/mirrors.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import time
import json
import pathlib
import urllib.parse
from pathlib import Path
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, Any, List, Optional, TYPE_CHECKING, Tuple
Expand Down Expand Up @@ -312,7 +313,10 @@ def run(self) -> MirrorConfiguration:


def select_mirror_regions(preset: Dict[str, List[MirrorStatusEntryV3]]) -> Dict[str, List[MirrorStatusEntryV3]]:
mirrors: Dict[str, List[MirrorStatusEntryV3]] = list_mirrors()
mirrors: Dict[str, List[MirrorStatusEntryV3]] | None = list_mirrors_from_remote()

if not mirrors:
mirrors = list_mirrors_from_local()

items = [MenuItem(name, value=(name, mirrors)) for name, mirrors in mirrors.items()]
group = MenuItemGroup(items, sort_items=True)
Expand All @@ -338,19 +342,41 @@ def select_mirror_regions(preset: Dict[str, List[MirrorStatusEntryV3]]) -> Dict[
selected_mirrors: List[Tuple[str, List[MirrorStatusEntryV3]]] = result.get_values()
return {name: mirror for name, mirror in selected_mirrors}

return {}


def select_custom_mirror(preset: List[CustomMirror] = []):
custom_mirrors = CustomMirrorList(preset).run()
return custom_mirrors


def sort_mirrors_by_performance(mirror_list: List[MirrorStatusEntryV3]) -> List[MirrorStatusEntryV3]:
def list_mirrors_from_remote() -> Optional[Dict[str, List[MirrorStatusEntryV3]]]:
if not storage['arguments']['offline']:
url = "https://archlinux.org/mirrors/status/json/"
attempts = 3

for attempt_nr in range(attempts):
try:
mirrorlist = fetch_data_from_url(url)
return _parse_remote_mirror_list(mirrorlist)
except Exception as e:
debug(f'Error while fetching mirror list: {e}')
time.sleep(attempt_nr + 1)

debug('Unable to fetch mirror list remotely, falling back to local mirror list')

return None


def list_mirrors_from_local() -> Dict[str, List[MirrorStatusEntryV3]]:
with Path('/etc/pacman.d/mirrorlist').open('r') as fp:
mirrorlist = fp.read()
return _parse_locale_mirrors(mirrorlist)


def _sort_mirrors_by_performance(mirror_list: List[MirrorStatusEntryV3]) -> List[MirrorStatusEntryV3]:
return sorted(mirror_list, key=lambda mirror: (mirror.score, mirror.speed))


def _parse_mirror_list(mirrorlist: str) -> Dict[str, List[MirrorStatusEntryV3]]:
def _parse_remote_mirror_list(mirrorlist: str) -> Dict[str, List[MirrorStatusEntryV3]]:
mirror_status = MirrorStatusListV3(**json.loads(mirrorlist))

sorting_placeholder: Dict[str, List[MirrorStatusEntryV3]] = {}
Expand Down Expand Up @@ -383,23 +409,41 @@ def _parse_mirror_list(mirrorlist: str) -> Dict[str, List[MirrorStatusEntryV3]]:
return sorted_by_regions


def list_mirrors() -> Dict[str, List[MirrorStatusEntryV3]]:
if not storage['arguments']['offline']:
url = "https://archlinux.org/mirrors/status/json/"
attempts = 3

for attempt_nr in range(attempts):
try:
mirrorlist = fetch_data_from_url(url)
return _parse_mirror_list(mirrorlist)
except Exception as e:
debug(f'Error while fetching mirror list: {e}')
time.sleep(attempt_nr + 1)

debug('Unable to fetch mirror list remotely, falling back to local mirror list')
def _parse_locale_mirrors(mirrorlist: str) -> Dict[str, List[MirrorStatusEntryV3]]:
lines = mirrorlist.splitlines()

# remove empty lines
lines = [line for line in lines if line]

mirror_list: Dict[str, List[MirrorStatusEntryV3]] = {}

current_region = ''
for idx, line in enumerate(lines):
line = line.strip()

if line.lower().startswith('server'):
if not current_region:
for i in range(idx - 1, 0, -1):
if lines[i].startswith('##'):
current_region = lines[i].replace('#', '').strip()
mirror_list.setdefault(current_region, [])
break

url = urllib.parse.urlparse(line.removeprefix('Server = '))
mirror_entry = MirrorStatusEntryV3(
url=url.rstrip('$repo/os/$arch'),
protocol=url.scheme,
active=True,
country=current_region or 'Worldwide',
# The following values are normally populated by
# archlinux.org mirror-list endpoint, and can't be known
# from just the local mirror-list file.
country_code='WW',
isos=True,
ipv4=True,
ipv6=True,
details='Locally defined mirror',
)
mirror_list[current_region].append(mirror_entry)

# we'll use the local mirror list if the offline flag is set
# or if fetching the mirror list remotely failed
with pathlib.Path('/etc/pacman.d/mirrorlist').open('r') as fp:
mirrorlist = fp.read()
return _parse_mirror_list(mirrorlist)
return mirror_list
10 changes: 7 additions & 3 deletions archinstall/lib/models/mirrors.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
)

from ..networking import ping, DownloadTimer
from ..output import info, debug
from ..output import debug


class MirrorStatusEntryV3(BaseModel):
Expand All @@ -36,6 +36,10 @@ class MirrorStatusEntryV3(BaseModel):
_port: int | None = None
_speedtest_retries: int | None = None

@property
def server_url(self) -> str:
return f'{self.url}$repo/os/$arch'

@property
def speed(self) -> float:
if self._speed is None:
Expand All @@ -46,7 +50,7 @@ def speed(self) -> float:

_retry = 0
while _retry < self._speedtest_retries and self._speed is None:
info(f"Checking download speed of {self._hostname}[{self.score}] by fetching: {self.url}core/os/x86_64/core.db")
debug(f"Checking download speed of {self._hostname}[{self.score}] by fetching: {self.url}core/os/x86_64/core.db")
req = urllib.request.Request(url=f"{self.url}core/os/x86_64/core.db")

try:
Expand Down Expand Up @@ -82,7 +86,7 @@ def latency(self) -> float | None:
We do this because some hosts blocks ICMP so we'll have to rely on .speed() instead which is slower.
"""
if self._latency is None:
info(f"Checking latency for {self.url}")
debug(f"Checking latency for {self.url}")
self._latency = ping(self._hostname, timeout=2)
debug(f" latency: {self._latency}")

Expand Down
11 changes: 7 additions & 4 deletions examples/config-sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,14 @@
"type": "manual",
"nics": [
{
"iface": null,
"ip": null,
"iface": "eno1",
"ip": "192.168.1.15/24",
"dhcp": true,
"gateway": null,
"dns": null
"gateway": "192.168.1.1",
"dns": [
"192.168.1.1",
"9.9.9.9"
]
}
]
},
Expand Down
3 changes: 2 additions & 1 deletion examples/creds-sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"sudo": true,
"username": "archinstall"
}
]
],
"encryption_password": "..."
}
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ dev = [
"mypy==1.13.0",
"flake8==7.1.1",
"pre-commit==4.0.1",
"ruff==0.7.2",
"ruff==0.7.3",
"pylint==3.3.1",
"pylint-pydantic==0.3.2",
]
Expand Down

0 comments on commit 065342c

Please sign in to comment.