• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rpm-software-management / rpmlint / 27743531775

18 Jun 2026 07:23AM UTC coverage: 88.143% (+0.2%) from 87.933%
27743531775

push

github

6096 of 6916 relevant lines covered (88.14%)

3.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.56
/rpmlint/cli.py
1
import argparse
4✔
2
from pathlib import Path
4✔
3
import sys
4✔
4

5
from rpmlint.helpers import print_warning
4✔
6
from rpmlint.lint import Lint
4✔
7
from rpmlint.rpmdiff import Rpmdiff
4✔
8
from rpmlint.version import __version__
4✔
9

10

11
__copyright__ = """
4✔
12
    Copyright (C) 2006 Mandriva
13
    Copyright (C) 2009 Red Hat, Inc.
14
    Copyright (C) 2009 Ville Skyttä
15
    Copyright (C) 2017 SUSE LINUX GmbH
16
    This program is free software; you can redistribute it and/or
17
    modify it under the terms of the GNU General Public License
18
    as published by the Free Software Foundation; either version 2
19
    of the License, or (at your option) any later version.
20

21
    This program is distributed in the hope that it will be useful,
22
    but WITHOUT ANY WARRANTY; without even the implied warranty of
23
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
    GNU General Public License for more details.
25

26
    You should have received a copy of the GNU General Public License
27
    along with this program; if not, write to the Free Software
28
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
29
"""
30

31

32
def process_diff_args(argv):
4✔
33
    """
34
    Process the passed arguments and return the result
35
    :param argv: passed arguments
36
    """
37

38
    parser = argparse.ArgumentParser(prog='rpmdiff',
×
39
                                     description='Shows basic differences between two rpm packages',
40
                                     epilog="""When using the -i or -e options,
41
                                               separate values from package arguments with '--',
42
                                               e.g.: 'rpmdiff -i 5 T -- old.rpm new.rpm' or place
43
                                               the options _after_ the package arguments.""")
44
    parser.add_argument('old_package', metavar='RPM_ORIG', type=Path, help='the old package')
×
45
    parser.add_argument('new_package', metavar='RPM_NEW', type=Path, help='the new package')
×
46
    parser.add_argument('-V', '--version', action='version', version=__version__, help='show package version and exit')
×
47
    parser.add_argument('-i', '--ignore', nargs='+', default=None, choices=['S', 'M', '5', 'D', 'N', 'L', 'V', 'U', 'G', 'F', 'T'],
×
48
                        help="""file property to ignore when calculating differences.
49
                                Valid values are: S (size), M (mode), 5 (checksum), D (device),
50
                                N (number of links), L (state), V (vflags), U (user), G (group),
51
                                F (fflags), T (time)""")
52
    parser.add_argument('-e', '--exclude', metavar='GLOB', nargs='+', default=None,
×
53
                        help="""Paths to exclude when showing differences.
54
                                Takes a glob. When absolute (starting with /)
55
                                all files in a matching directory are excluded as well.
56
                                When relative, files matching the pattern anywhere
57
                                are excluded but not directory contents.""")
58

59
    options = parser.parse_args(args=argv)
×
60

61
    # convert options to dict
62
    options_dict = vars(options)
×
63
    return options_dict
×
64

65

66
def process_lint_args(argv):
4✔
67
    """
68
    Process the passed arguments and return the result
69
    :param argv: passed arguments
70
    """
71

72
    parser = argparse.ArgumentParser(prog='rpmlint',
4✔
73
                                     description='Check for common problems in rpm packages')
74
    parser.add_argument('rpmfile', nargs='*', type=Path, help='files to be validated by rpmlint')
4✔
75
    parser.add_argument('-V', '--version', action='version', version=__version__, help='show package version and exit')
4✔
76
    parser.add_argument('-c', '--config', type=_validate_conf_location, help='load up additional configuration data from specified path (file or directory with *.toml files)')
4✔
77
    parser.add_argument('-e', '--explain', nargs='+', default='', help='provide detailed explanation for one specific message id')
4✔
78
    parser.add_argument('-r', '--rpmlintrc', '--file', action='append', type=_is_file_path, help='load up specified rpmlintrc file (may be repeated)')
4✔
79
    parser.add_argument('-v', '--verbose', '--info', action='store_true', help='provide detailed explanations where available')
4✔
80
    parser.add_argument('-p', '--print-config', action='store_true', help='print the settings that are in effect when using the rpmlint')
4✔
81
    parser.add_argument('-i', '--installed', nargs='+', default='', help='installed packages to be validated by rpmlint')
4✔
82
    parser.add_argument('-t', '--time-report', action='store_true', help='print time report for run checks')
4✔
83
    parser.add_argument('-T', '--profile', action='store_true', help='print cProfile report')
4✔
84
    parser.add_argument('--ignore-unused-rpmlintrc', action='store_true',
4✔
85
                        help='Do not report "unused-rpmlintrc-filter" errors')
4✔
86
    parser.add_argument('--checks',
87
                        help='Debugging option that enables only selected checks (separated by comma)')
4✔
88
    lint_modes_parser = parser.add_mutually_exclusive_group()
89
    lint_modes_parser.add_argument('-s', '--strict', action='store_true', help='treat all messages as errors')
4✔
90
    lint_modes_parser.add_argument('-P', '--permissive', action='store_true', help='treat individual errors as non-fatal')
4✔
91

4✔
92
    # print help if there is no argument
93
    if len(argv) < 1:
94
        parser.print_help()
4✔
95
        sys.exit(0)
×
96

×
97
    options = parser.parse_args(args=argv)
98

4✔
99
    # validate all the rpmfile options to be either file or folder
100
    f_path = set()
101
    invalid_path = False
4✔
102
    for item in options.rpmfile:
4✔
103
        p_path = Path()
4✔
104
        pattern = None
4✔
105
        for pos, component in enumerate(item.parts):
4✔
106
            if ('*' in component) or ('?' in component):
4✔
107
                pattern = '/'.join(item.parts[pos:])
4✔
108
                break
×
109
            p_path = p_path / component
×
110
        p_path = list(p_path.glob(pattern)) if pattern else [p_path]
4✔
111

4✔
112
        for path in p_path:
113
            if not path.exists():
4✔
114
                print_warning(f"The file or directory '{path}' does not exist")
4✔
115
                invalid_path = True
×
116
        f_path.update(p_path)
×
117

4✔
118
    if invalid_path:
119
        sys.exit(2)
4✔
120
    # convert options to dict
×
121
    options_dict = vars(options)
122
    # use computed rpmfile
4✔
123
    options_dict['rpmfile'] = list(f_path)
124
    return options_dict
4✔
125

4✔
126

127
def _validate_conf_location(string):
128
    """
4✔
129
    Help validate configuration location during argument parsing.
130

131
    We accept either one configuration file or a directory (then it processes
132
    all *.toml files in this directory). It exits the program if location
133
    doesn't exist.
134

135
    Args:
136
        string: A string representing configuration path (file or directory).
137

138
    Returns:
139
        A list with individual paths for each configuration file found.
140
    """
141
    config_paths = []
142
    path = Path(string)
4✔
143

4✔
144
    # Exit if file or dir doesn't exist
145
    if not path.exists():
146
        print_warning(
4✔
147
            f"File or dir with user specified configuration '{string}' does not exist")
4✔
148
        sys.exit(2)
149

4✔
150
    if path.is_dir():
151
        config_paths.extend(path.glob('*.toml'))
4✔
152
    elif path.is_file():
2✔
153
        config_paths.append(path)
4✔
154

4✔
155
    return config_paths
156

4✔
157

158
def _is_file_path(path):
159
    p = Path(path)
4✔
160
    if not p.is_file():
×
161
        raise argparse.ArgumentTypeError(f'{path} is not a valid file path')
×
162
    return p
×
163

×
164

165
def lint():
166
    """
4✔
167
    Main wrapper for lint command processing
168
    """
169
    options = process_lint_args(sys.argv[1:])
170

171
    sys.exit(Lint(options).run())
×
172

×
173

174
def diff():
175
    """
×
176
    Main wrapper for diff command processing
×
177
    """
178
    options = process_diff_args(sys.argv[1:])
×
179
    d = Rpmdiff(options['old_package'], options['new_package'],
180
                ignore=options['ignore'], exclude=options['exclude'])
181
    textdiff = d.textdiff()
4✔
182
    if textdiff:
183
        print(textdiff)
184
    sys.exit(int(d.differs()))
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc