pmbootstrap-meow/pmb/__init__.py
Caleb Connolly 6087a9df8f
core: don't re-export get_context (MR 2252)
This makes testing a lot more annoying.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-23 12:38:40 +02:00

128 lines
4 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 Any, Optional
from pmb.helpers.exceptions import BuildFailedError, NonBugError
from . import config
from . import parse
from . import types
from .config import init as config_init
from .helpers import frontend
from .helpers import logging
from .helpers import mount
from .helpers import other
from .core import Chroot, Config
from .core.context import get_context
from .commands import run_command
# pmbootstrap version
__version__ = "2.3.1"
# Python version check
version = sys.version_info
if version < (3, 9):
print("You need at least Python 3.9 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)
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
# FIXME: can't use PmbArgs here because it creates a circular import
args: Any
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!")
# Initialize or require config
if args.action == "init":
return config_init.frontend(args)
elif not os.path.exists(args.config):
raise RuntimeError("Please specify a config file, or run"
" 'pmbootstrap init' to generate one.")
elif not os.path.exists(context.config.work):
raise RuntimeError("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(args)
# 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
if "args" not in locals():
import logging as pylogging
pylogging.getLogger().setLevel(logging.DEBUG)
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.com/postmarketOS/pmbootstrap/-/tags")
print(f"Your version: {__version__}")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())