1
0
Fork 1
mirror of https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git synced 2025-07-13 03:19:47 +03:00
pmbootstrap/pmb/__init__.py
2025-05-13 19:42:56 +02:00

161 lines
5.2 KiB
Python

# Copyright 2023 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
# PYTHON_ARGCOMPLETE_OK
import sys
import os
import traceback
from typing import TYPE_CHECKING
from pathlib import Path
from pmb.helpers.exceptions import BuildFailedError, NonBugError
if TYPE_CHECKING:
from pmb.types import PmbArgs
from . import config
from . import parse
from .config import init as config_init, require_programs
from .helpers import frontend as frontend
from .helpers import logging
from .helpers import mount
from .helpers import other
from .helpers import status
from .core import Chroot, Config
from .core.context import get_context
from .commands import run_command
# pmbootstrap version
__version__ = "3.4.0"
# Python version check
# === CHECKLIST FOR UPGRADING THE REQUIRED PYTHON VERSION ===
# * .ci/vermin.sh
# * README.md
# * docs/usage.rst
# * pmb/__init__.py (you are here)
# * pyproject.toml
# * when upgrading to python 3.11: pmb/helpers/toml.py and remove this line
version = sys.version_info
if version < (3, 10):
print("You need at least Python 3.10 to run pmbootstrap")
print("(You are running it with Python " + str(version.major) + "." + str(version.minor) + ")")
sys.exit()
def print_log_hint() -> None:
context = get_context(allow_failure=True)
if context and context.details_to_stdout:
return
log = context.log if context else Config().work / "log.txt"
# Hints about the log file (print to stdout only)
log_hint = "Run 'pmbootstrap log' for details."
if not os.path.exists(log):
log_hint += (
" Alternatively you can use '--details-to-stdout' to get more"
" output, e.g. 'pmbootstrap --details-to-stdout init'."
)
print()
print(log_hint)
def main() -> int:
# Wrap everything to display nice error messages
args: PmbArgs
try:
# Parse arguments, set up logging
args = parse.arguments()
context = get_context()
os.umask(0o22)
# Store script invocation command
os.environ["PMBOOTSTRAP_CMD"] = sys.argv[0]
# Sanity checks
other.check_grsec()
if not args.as_root and os.geteuid() == 0:
raise RuntimeError("Do not run pmbootstrap as root!")
# Check for required programs (and find their absolute paths)
require_programs()
# Initialize or require config
if args.action == "init":
config_init.frontend(args)
return 0
elif not os.path.exists(args.config):
if args.config != config.defaults["config"]:
raise NonBugError(f"Couldn't find file passed with --config: {args.config}")
old_config = (
Path(os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser("~/.config"))
/ "pmbootstrap.cfg"
)
if os.path.exists(old_config):
raise NonBugError(
f"Thanks for upgrading to pmbootstrap {__version__}!"
" The config file format has changed, please generate a new config with"
" 'pmbootstrap init'."
)
raise NonBugError(
"Run 'pmbootstrap init' first to generate a config file (or use --config)."
)
elif not os.path.exists(context.config.work):
raise NonBugError("Work path not found, please run 'pmbootstrap init' to create it.")
# Migrate work folder if necessary
if args.action not in ["shutdown", "zap", "log"]:
other.migrate_work_folder()
# Run the function with the action's name (in pmb/helpers/frontend.py)
if args.action:
run_command(args)
else:
logging.info("Run pmbootstrap -h for usage information.")
# Still active notice
if mount.ismount(Chroot.native() / "dev"):
logging.info("NOTE: chroot is still active (use 'pmbootstrap shutdown' as necessary)")
logging.info("DONE!")
except KeyboardInterrupt:
print("\nCaught KeyboardInterrupt, exiting …")
sys.exit(130) # SIGINT(2) + 128
except NonBugError as exception:
logging.error(f"ERROR: {exception}")
return 2
except BuildFailedError as exception:
logging.error(f"ERROR: {exception}")
print_log_hint()
return 3
except Exception as e:
# Dump log to stdout when args (and therefore logging) init failed
can_print_status = get_context(allow_failure=True) is not None
if "args" not in locals():
import logging as pylogging
pylogging.getLogger().setLevel(logging.DEBUG)
can_print_status = False
logging.info("ERROR: " + str(e))
logging.info("See also: <https://postmarketos.org/troubleshooting>")
logging.debug(traceback.format_exc())
print_log_hint()
print()
print("Before you report this error, ensure that pmbootstrap is up to date.")
print(
"Find the latest version here: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/tags"
)
print(f"Your version: {__version__}")
if can_print_status:
status.print_status()
return 1
return 0
if __name__ == "__main__":
sys.exit(main())