%PDF- %PDF-
Direktori : /bin/ |
Current File : //bin/apport-unpack |
#!/usr/bin/python3 # Copyright (c) 2006 Canonical Ltd. # Author: Martin Pitt <martin.pitt@ubuntu.com> # # 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 the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. See http://www.gnu.org/copyleft/gpl.html for # the full text of the license. """Extract the fields of a problem report into separate files into a new or empty directory.""" # pylint: disable=invalid-name # pylint: enable=invalid-name import argparse import contextlib import gettext import gzip import io import os import sys from collections.abc import Iterator from gettext import gettext as _ from typing import BinaryIO import problem_report from apport import fatal def parse_args() -> argparse.Namespace: """Parse command line arguments.""" parser = argparse.ArgumentParser(usage=_("%(prog)s <report> <target directory>")) parser.add_argument("report", help=_("Report file to unpack")) parser.add_argument("target_directory", help=_("directory to unpack report to")) return parser.parse_args() @contextlib.contextmanager def open_report(report_filename: str) -> Iterator[(BinaryIO | gzip.GzipFile)]: """Open a problem report from given filename.""" if report_filename == "-": # sys.stdin has type io.TextIOWrapper, not the claimed io.TextIO. # See https://github.com/python/typeshed/issues/10093 assert isinstance(sys.stdin, io.TextIOWrapper) yield sys.stdin.detach() elif report_filename.endswith(".gz"): with gzip.open(report_filename, "rb") as report_file: yield report_file else: with open(report_filename, "rb") as report_file: yield report_file def unpack_report_to_directory( report: problem_report.ProblemReport, target_directory: str ) -> list[str]: """Write each report entry into a separate file. Return a list of keys that were not loaded. """ missing_keys = [] for key, value in report.items(): if value is None: missing_keys.append(key) continue with open(os.path.join(target_directory, key), "wb") as key_file: if isinstance(value, str): key_file.write(value.encode("UTF-8")) else: key_file.write(value) return missing_keys # pylint: disable-next=missing-function-docstring def main() -> None: gettext.textdomain("apport") args = parse_args() # ensure that the directory does not yet exist or is empty try: if os.path.isdir(args.target_directory): if os.listdir(args.target_directory): fatal(_("Destination directory exists and is not empty.")) else: os.mkdir(args.target_directory) except OSError as error: fatal("%s", str(error)) report = problem_report.ProblemReport() try: with open_report(args.report) as report_file: # In case of passing the report to stdin, # the report needs to be loaded in one go. # The current implementation loads the whole report into memory. report.load(report_file, binary=args.report == "-") except (OSError, problem_report.MalformedProblemReport) as error: fatal("%s", str(error)) bin_keys = unpack_report_to_directory(report, args.target_directory) if bin_keys: try: with open_report(args.report) as report_file: report.extract_keys(report_file, bin_keys, args.target_directory) except (OSError, problem_report.MalformedProblemReport) as error: fatal("%s", str(error)) if __name__ == "__main__": main()