Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions archinstall/lib/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@
from archinstall.lib.models.packages import Repository
from archinstall.lib.models.profile_model import ProfileConfiguration
from archinstall.lib.models.users import Password, User
from archinstall.lib.output import debug, error, warn
from archinstall.lib.output import debug, error, logger, warn
from archinstall.lib.plugins import load_plugin
from archinstall.lib.storage import storage
from archinstall.lib.translationhandler import Language, tr, translation_handler
from archinstall.lib.utils.util import get_password
from archinstall.tui.curses_menu import Tui
Expand Down Expand Up @@ -389,7 +388,7 @@ def _parse_args(self) -> Arguments:
args.silent = False

if args.debug:
warn(f'Warning: --debug mode will write certain credentials to {storage["LOG_PATH"]}/{storage["LOG_FILE"]}!')
warn(f'Warning: --debug mode will write certain credentials to {logger.path}!')

if args.plugin:
plugin_path = Path(args.plugin)
Expand Down
5 changes: 2 additions & 3 deletions archinstall/lib/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
from .args import ArchConfig
from .crypt import encrypt
from .general import JSON, UNSAFE_JSON
from .output import debug, warn
from .storage import storage
from .output import debug, logger, warn
from .utils.util import get_password, prompt_dir


Expand All @@ -29,7 +28,7 @@ def __init__(self, config: ArchConfig):
"""

self._config = config
self._default_save_path = storage.get('LOG_PATH', Path('.'))
self._default_save_path = logger.directory
self._user_config_file = Path('user_configuration.json')
self._user_creds_file = Path('user_credentials.json')

Expand Down
5 changes: 2 additions & 3 deletions archinstall/lib/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
from typing import Any, override

from .exceptions import RequirementError, SysCallError
from .output import debug, error
from .storage import storage
from .output import debug, error, logger

# https://stackoverflow.com/a/43627833/929999
_VT100_ESCAPE_REGEX = r'\x1B\[[?0-9;]*[a-zA-Z]'
Expand Down Expand Up @@ -415,7 +414,7 @@ def trace_log(self) -> bytes | None:


def _append_log(file: str, content: str) -> None:
path = Path(f'{storage["LOG_PATH"]}/{file}')
path = logger.directory / file

change_perm = not path.exists()

Expand Down
18 changes: 8 additions & 10 deletions archinstall/lib/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from .models.mirrors import MirrorConfiguration
from .models.network_configuration import Nic
from .models.users import User
from .output import debug, error, info, log, warn
from .output import debug, error, info, log, logger, warn
from .pacman import Pacman
from .pacman.config import PacmanConfig
from .plugins import plugins
Expand Down Expand Up @@ -132,13 +132,12 @@ def __exit__(self, exc_type: type[BaseException] | None, exc_val, exc_tb: Traceb

# We avoid printing /mnt/<log path> because that might confuse people if they note it down
# and then reboot, and a identical log file will be found in the ISO medium anyway.
log_file = os.path.join(storage['LOG_PATH'], storage['LOG_FILE'])
Tui.print(str(tr('[!] A log file has been created here: {}').format(log_file)))
Tui.print(str(tr('[!] A log file has been created here: {}').format(logger.path)))
Tui.print(tr('Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues'))
raise exc_val

if not (missing_steps := self.post_install_check()):
msg = f'Installation completed without any errors.\nLog files temporarily available at {storage["LOG_PATH"]}.\nYou may reboot when ready.\n'
msg = f'Installation completed without any errors.\nLog files temporarily available at {logger.directory}.\nYou may reboot when ready.\n'
log(msg, fg='green')
self.sync_log_to_install_medium()
return True
Expand All @@ -148,7 +147,7 @@ def __exit__(self, exc_type: type[BaseException] | None, exc_val, exc_tb: Traceb
for step in missing_steps:
warn(f' - {step}')

warn(f'Detailed error logs can be found at: {storage["LOG_PATH"]}')
warn(f'Detailed error logs can be found at: {logger.directory}')
warn('Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues')

self.sync_log_to_install_medium()
Expand Down Expand Up @@ -456,13 +455,12 @@ def sync_log_to_install_medium(self) -> bool:
# Copy over the install log (if there is one) to the install medium if
# at least the base has been strapped in, otherwise we won't have a filesystem/structure to copy to.
if self._helper_flags.get('base-strapped', False) is True:
if filename := storage.get('LOG_FILE', None):
absolute_logfile = os.path.join(storage.get('LOG_PATH', './'), filename)
absolute_logfile = logger.path

if not os.path.isdir(f'{self.target}/{os.path.dirname(absolute_logfile)}'):
os.makedirs(f'{self.target}/{os.path.dirname(absolute_logfile)}')
if not os.path.isdir(f'{self.target}/{os.path.dirname(absolute_logfile)}'):
os.makedirs(f'{self.target}/{os.path.dirname(absolute_logfile)}')

shutil.copy2(absolute_logfile, f'{self.target}/{absolute_logfile}')
shutil.copy2(absolute_logfile, f'{self.target}/{absolute_logfile}')

return True

Expand Down
67 changes: 36 additions & 31 deletions archinstall/lib/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any

from .storage import storage
from .utils.unicode import unicode_ljust, unicode_rjust

if TYPE_CHECKING:
Expand Down Expand Up @@ -147,30 +146,46 @@ def log(message: str, level: int = logging.DEBUG) -> None:
log_adapter.log(level, message)


def _check_log_permissions() -> None:
filename = storage.get('LOG_FILE', None)
log_dir = storage.get('LOG_PATH', Path('./'))
class Logger:
def __init__(self, path: Path = Path('/var/log/archinstall')) -> None:
self._path = path

if not filename:
raise ValueError('No log file name defined')
@property
def path(self) -> Path:
return self._path / 'install.log'

log_file = log_dir / filename
@property
def directory(self) -> Path:
return self._path

try:
log_dir.mkdir(exist_ok=True, parents=True)
log_file.touch(exist_ok=True)
def _check_permissions(self) -> None:
log_file = self.path

with log_file.open('a') as fp:
fp.write('')
except PermissionError:
# Fallback to creating the log file in the current folder
fallback_dir = Path('./').absolute()
fallback_log_file = fallback_dir / filename
try:
self._path.mkdir(exist_ok=True, parents=True)
log_file.touch(exist_ok=True)

with log_file.open('a') as f:
f.write('')
except PermissionError:
# Fallback to creating the log file in the current folder
logger._path = Path('./').absolute()

warn(
f'Not enough permission to place log file at {log_file},',
'creating it in {logger.path} instead'
)

def log(self, level: int, content: str) -> None:
self._check_permissions()

fallback_log_file.touch(exist_ok=True)
with self.path.open('a') as f:
ts = _timestamp()
level_name = logging.getLevelName(level)
f.write(f'[{ts}] - {level_name} - {content}\n')

storage['LOG_PATH'] = fallback_dir
warn(f'Not enough permission to place log file at {log_file}, creating it in {fallback_log_file} instead')

logger = Logger()


def _supports_color() -> bool:
Expand Down Expand Up @@ -309,25 +324,15 @@ def log(
reset: bool = False,
font: list[Font] = [],
) -> None:
# leave this check here as we need to setup the logging
# right from the beginning when the modules are loaded
_check_log_permissions()
text = ' '.join([str(x) for x in msgs])

text = orig_string = ' '.join([str(x) for x in msgs])
logger.log(level, text)

# Attempt to colorize the output if supported
# Insert default colors and override with **kwargs
if _supports_color():
text = _stylize_output(text, fg, bg, reset, font)

log_file = storage['LOG_PATH'] / storage['LOG_FILE']

with log_file.open('a') as fp:
ts = _timestamp()
level_name = logging.getLevelName(level)
out = f'[{ts}] - {level_name} - {orig_string}\n'
fp.write(out)

Journald.log(text, level=level)

if level != logging.DEBUG:
Expand Down
8 changes: 1 addition & 7 deletions archinstall/lib/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# (4. Added the ~/.config directory as an additional option for future reasons)
#
# And Keeping this in dict ensures that variables are shared across imports.
from pathlib import Path
from typing import TYPE_CHECKING, NotRequired, TypedDict

if TYPE_CHECKING:
Expand All @@ -14,13 +13,8 @@


class _StorageDict(TypedDict):
LOG_FILE: Path
LOG_PATH: Path
active_boot: NotRequired['Boot | None']
installation_session: NotRequired['Installer']


storage: _StorageDict = {
'LOG_FILE': Path('install.log'),
'LOG_PATH': Path('/var/log/archinstall'),
}
storage: _StorageDict = {}