blob: 1cfe86e8d556411a689607859ce6ad270ebab63c [file] [log] [blame]
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Copyright 1999-2021 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
import collections
import io
import logging
import sys
# import our centrally initialized portage instance
from repoman._portage import portage
portage._internal_caller = True
portage._disable_legacy_globals()
from portage import os
import portage.checksum
import portage.const
import portage.repository.config
from portage.output import create_color_func, nocolor
from portage.output import ConsoleStyleFile, StyleWriter
from portage.util import formatter
from portage.util.futures.extendedfutures import (
ExtendedFuture,
)
# pylint: disable=ungrouped-imports
from repoman.actions import Actions
from repoman.argparser import parse_args
from repoman.qa_data import QAData
from repoman.qa_data import format_qa_output, format_qa_output_column
from repoman.repos import RepoSettings
from repoman.scanner import Scanner
from repoman import utilities
from repoman.modules.vcs.settings import VCSSettings
from repoman import VERSION
bad = create_color_func("BAD")
# A sane umask is needed for files that portage creates.
os.umask(0o22)
LOGLEVEL = logging.WARNING
portage.util.initialize_logger(LOGLEVEL)
VALID_VERSIONS = [
1,
]
_repoman_main_vars = collections.namedtuple(
"_repoman_main_vars",
(
"can_force",
"exitcode",
"options",
"qadata",
"repo_settings",
"scanner",
"vcs_settings",
),
)
def repoman_main(argv):
repoman_vars = _repoman_init(argv)
if repoman_vars.exitcode is not None:
return repoman_vars.exitcode
result = _repoman_scan(*repoman_vars)
return _handle_result(*repoman_vars, result)
def _repoman_init(argv):
config_root = os.environ.get("PORTAGE_CONFIGROOT")
repoman_settings = portage.config(config_root=config_root, local_config=False)
repoman_settings.valid_versions = VALID_VERSIONS
if (
repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true")
or repoman_settings.get("TERM") == "dumb"
or not sys.stdout.isatty()
):
nocolor()
options, arguments = parse_args(
argv, repoman_settings.get("REPOMAN_DEFAULT_OPTS", "")
)
if options.version:
print("Repoman", VERSION, "(portage-%s)" % portage.VERSION)
return _repoman_main_vars(None, 0, None, None, None, None, None)
logger = logging.getLogger()
if options.verbosity > 0:
logger.setLevel(LOGLEVEL - 10 * options.verbosity)
else:
logger.setLevel(LOGLEVEL)
# Set this to False when an extraordinary issue (generally
# something other than a QA issue) makes it impossible to
# commit (like if Manifest generation fails).
can_force = ExtendedFuture(True)
repo_settings, vcs_settings, scanner, qadata = _create_scanner(
options, can_force, config_root, repoman_settings
)
return _repoman_main_vars(
can_force, None, options, qadata, repo_settings, scanner, vcs_settings
)
def _create_scanner(options, can_force, config_root, repoman_settings):
portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
if portdir is None:
return (None, None, None, None)
myreporoot = os.path.basename(portdir_overlay)
myreporoot += mydir[len(portdir_overlay) :]
# avoid a circular parameter repo_settings
vcs_settings = VCSSettings(options, repoman_settings)
qadata = QAData()
logging.debug("repoman_main: RepoSettings init")
repo_settings = RepoSettings(
config_root,
portdir,
portdir_overlay,
repoman_settings,
vcs_settings,
options,
qadata,
)
repoman_settings = repo_settings.repoman_settings
repoman_settings.valid_versions = VALID_VERSIONS
# Now set repo_settings
vcs_settings.repo_settings = repo_settings
# set QATracker qacats, qawarnings
vcs_settings.qatracker.qacats = repo_settings.qadata.qacats
vcs_settings.qatracker.qawarnings = repo_settings.qadata.qawarnings
logging.debug("repoman_main: vcs_settings done")
logging.debug("repoman_main: qadata: %s", repo_settings.qadata)
if "digest" in repoman_settings.features and options.digest != "n":
options.digest = "y"
logging.debug("vcs: %s" % (vcs_settings.vcs,))
logging.debug("repo config: %s" % (repo_settings.repo_config,))
logging.debug("options: %s" % (options,))
# It's confusing if these warnings are displayed without the user
# being told which profile they come from, so disable them.
env = os.environ.copy()
env["FEATURES"] = env.get("FEATURES", "") + " -unknown-features-warn"
# Perform the main checks
scanner = Scanner(
repo_settings, myreporoot, config_root, options, vcs_settings, mydir, env
)
return repo_settings, vcs_settings, scanner, qadata
def _repoman_scan(
can_force, exitcode, options, qadata, repo_settings, scanner, vcs_settings
):
scanner.scan_pkgs(can_force)
if options.if_modified == "y" and len(scanner.effective_scanlist) < 1:
logging.warning(
"--if-modified is enabled, but no modified packages were found!"
)
result = {
# fail will be true if we have failed in at least one non-warning category
"fail": 0,
# warn will be true if we tripped any warnings
"warn": 0,
# full will be true if we should print a "repoman full" informational message
"full": options.mode != "full",
}
for x in qadata.qacats:
if x not in vcs_settings.qatracker.fails:
continue
result["warn"] = 1
if x not in qadata.qawarnings:
result["fail"] = 1
if result["fail"] or (
result["warn"] and not (options.quiet or options.mode == "scan")
):
result["full"] = 0
return result
def _handle_result(
can_force, exitcode, options, qadata, repo_settings, scanner, vcs_settings, result
):
commitmessage = None
if options.commitmsg:
commitmessage = options.commitmsg
elif options.commitmsgfile:
# we don't need the actual text of the commit message here
# the filename will do for the next code block
commitmessage = options.commitmsgfile
# Save QA output so that it can be conveniently displayed
# in $EDITOR while the user creates a commit message.
# Otherwise, the user would not be able to see this output
# once the editor has taken over the screen.
qa_output = io.StringIO()
style_file = ConsoleStyleFile(sys.stdout)
if options.mode == "commit" and (not commitmessage or not commitmessage.strip()):
style_file.write_listener = qa_output
console_writer = StyleWriter(file=style_file, maxcol=9999)
console_writer.style_listener = style_file.new_styles
f = formatter.AbstractFormatter(console_writer)
format_outputs = {"column": format_qa_output_column, "default": format_qa_output}
format_output = format_outputs.get(options.output_style, format_outputs["default"])
format_output(
f,
vcs_settings.qatracker.fails,
result["full"],
result["fail"],
options,
qadata.qawarnings,
)
style_file.flush()
del console_writer, f, style_file
# early out for manifest generation
if options.mode == "manifest":
return 1 if result["fail"] else 0
qa_output = qa_output.getvalue()
qa_output = qa_output.splitlines(True)
# output the results
actions = Actions(repo_settings, options, scanner, vcs_settings)
if actions.inform(can_force.get(), result):
# perform any other actions
actions.perform(qa_output)
elif result["fail"]:
return 1
return 0