Completed
Push — develop ( 85e641...51e497 )
by Thomas
01:23
created

parsecli()   F

Complexity

Conditions 18

Size

Total Lines 195

Duplication

Lines 0
Ratio 0 %

Importance

Changes 12
Bugs 0 Features 0
Metric Value
cc 18
c 12
b 0
f 0
dl 0
loc 195
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like parsecli() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#
2
# Copyright (c) 2015 SUSE Linux GmbH
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of version 3 of the GNU General Public License as
6
# published by the Free Software Foundation.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, contact SUSE LLC.
15
#
16
# To contact SUSE about this file by physical or electronic mail,
17
# you may find current contact information at www.suse.com
18
19
import argparse
20
from configparser import NoOptionError, NoSectionError
21
22
from .. import __version__
23
from ..config import docmanagerconfig, create_userconfig
24
from ..core import ReturnCodes, DEFAULT_DM_PROPERTIES, DEFAULT_PROCESSES
25
from ..logmanager import log, logmgr_flog, setloglevel
26
27
from .checks import *
28
from .cmd_alias import alias_subcmd, rewrite_alias
29
from .cmd_analyze import analyze_subcmd
30
from .cmd_config import config_subcmd
31
from .cmd_del import del_subcmd
32
from .cmd_get import get_subcmd
33
from .cmd_init import init_subcmd
34
from .cmd_set import set_subcmd
35
from .cmd_setattr import setattr_subcmd
36
from .cmd_delattr import delattr_subcmd
37
from .cmd_getattr import getattr_subcmd
38
39
from glob import glob
40
import re
41
import os
42
import shlex
43
import sys
44
import urllib.request
45
46
47
48
def parsecli(cliargs=None, error_on_config=False):
49
    """Parse command line arguments
50
51
    :param list cliargs: Arguments to parse or None (=use sys.argv)
52
    :return: parsed arguments
53
    :rtype: argparse.Namespace
54
    """
55
56
    # parse just --config and --verbose
57
    confparser = argparse.ArgumentParser(add_help=False)
58
    confparser.add_argument('--config', dest='configfile', metavar='CONFIGFILE',
59
                            help='user config file location, uses also '
60
                                 'XDG_CONFIG_HOME env variable if set')
61
    confparser.add_argument('-v', '--verbose', action='count',
62
                            help="Increase verbosity level")
63
    args, remaining_argv = confparser.parse_known_args(cliargs)
64
65
    # Store configuration filename for further usage:
66
    configfile = args.configfile
67
    config = None
68
69
    # init log module
70
    setloglevel(args.verbose)
71
72
    # init config module
73
    # Exception handled in __init__.py
74
    config = docmanagerconfig(args.configfile)
75
76
    # Read the log level from the config files
77
    try:
78
        verbosity_level = int(config["general"]["verbosity_level"])
79
80
        if args.verbose is not None:
81
            if verbosity_level > args.verbose:
82
                args.verbose =  verbosity_level
83
        else:
84
            args.verbose = verbosity_level
85
86
        # set log level
87
        setloglevel(args.verbose)
88
    except KeyError:
89
        pass
90
91
    if remaining_argv:
92
        alias = remaining_argv[0]
93
94
        # parse aliases
95
        if is_alias(alias) and not alias.startswith('-'):
96
            remaining_argv = remaining_argv[1:]
97
98
            try:
99
                value = parse_alias_value("{alias} {args}".format(alias=config.get("alias", alias),
100
                                                args=" ".join(remaining_argv)))
101
                cliargs = shlex.split(value)
102
            except (NoSectionError, NoOptionError) as err:
103
                pass
104
105
    # parse cli parameters
106
    filesargs = dict(nargs='+',
107
                     metavar="FILE",
108
                     help='One or more DocBook XML or DC files.'
109
                     )
110
    propargs = dict(action='append',
111
                    # metavar="PROP[[=VALUE],PROP[=VALUE]...]
112
                    help='One or more properties to get, set, delete, or get-attr. '
113
                         'Syntax of PROPERTIES: PROP[[=VALUE],PROP[=VALUE]...]'
114
                         ' Example (get/del): -p foo or -p foo,bar or '
115
                         '-p foo -p bar '
116
                         'Example (set): -p foo=a or -p foo=a,bar=b or '
117
                         '-p foo=a -p bar=b'
118
                    )
119
    stop_on_error = dict(action='store_true',
120
                       default=False,
121
                       help='Stop if an (XML) error is found '
122
                            'in a XML file (default: %(default)s)'
123
                )
124
    queryformat = dict(action='store',
125
                       help='The output query format. For more information, have a look into the manual page.'
126
                )
127
    sort = dict(action='store',
128
                       help='Sorts the output by XML properties.'
129
                )
130
    filters = dict(action='append',
131
                       help='Filters the analyzed data. For more information, have a look into the manual page.'
132
                )
133
    default_output = dict(action='store',
134
                       help='Sets the default output for properties which are not available in a file. By default, DocManager prints nothing.'
135
                )
136
    quiet = dict(action='store_true',
137
                       help='DocManager will print nothing or in some cases only the relevant output.'
138
                )
139
    prop = dict(action='store', help='The property which gets modified.')
140
    attributes = dict(action='append', help='One or more attributes to get, set, or delete.'
141
                                            'Syntax of ATTRIBUTES: ATTR[[=VALUE],ATTR[=VALUE]...]'
142
                                            ' Example (attr-get/attr-del): -a foo or -a foo,bar or '
143
                                            '-a foo -a bar '
144
                                            'Example (attr-set): -a foo=a or -a foo=a,bar=b or '
145
                                            '-a foo=a -a bar=b')
146
    mainprops = tuple(("-{}".format(i.upper()[0]), "--{}".format(i))
147
                      for i in DEFAULT_DM_PROPERTIES)
148
149
    parser = argparse.ArgumentParser(
150
        prog="docmanager",
151
        parents=[confparser],
152
        # usage="%(prog)s COMMAND [OPTIONS] FILE [FILE ...]\n",
153
        description="Docmanager sets, gets, deletes, or queries "
154
                    "meta-information for DocBook5 XML files.")
155
    parser.add_argument('--version',
156
                        action='version',
157
                        version='%(prog)s ' + __version__
158
                        )
159
    parser.add_argument('--langlist',
160
                        action='store_true'
161
                        )
162
    parser.add_argument('-j', '--jobs',
163
                        type=int,
164
                        default=DEFAULT_PROCESSES,
165
                        action='store',
166
                        help='The amount of jobs for parsing all XML files.'
167
                        )
168
169
    # Create a subparser for all of our subcommands,
170
    # save the subcommand in 'dest'
171
    subparsers = parser.add_subparsers(
172
        dest='action',
173
        title="Available subcommands",
174
        # metavar="COMMAND"
175
        )
176
177
    init_subcmd(subparsers, stop_on_error, propargs, mainprops, filesargs)
178
    get_subcmd(subparsers, quiet, propargs, filesargs)
179
    set_subcmd(subparsers, stop_on_error, propargs, mainprops, filesargs)
180
    del_subcmd(subparsers, propargs, filesargs)
181
    setattr_subcmd(subparsers, stop_on_error, prop, attributes, filesargs)
182
    delattr_subcmd(subparsers, stop_on_error, prop, attributes, filesargs)
183
    getattr_subcmd(subparsers, stop_on_error, propargs, attributes, filesargs)
184
    analyze_subcmd(subparsers, queryformat, filters, sort, quiet, stop_on_error, default_output, filesargs)
185
    config_subcmd(subparsers)
186
    alias_subcmd(subparsers)
187
188
    # -----
189
    args = parser.parse_args(args=cliargs)
190
191
    if args.configfile is None:
192
        args.configfile = configfile
193
194
    args.config = config
195
196
    ##
197
    rewrite_alias(args)
198
199
    # Display language list
200
    if args.langlist is True:
201
        show_langlist()
202
203
    # If docmanager is called without anything, print the help and exit
204
    if args.action is None:
205
        parser.print_help()
206
        sys.exit(ReturnCodes.E_CALL_WITHOUT_PARAMS)
207
208
    if not hasattr(args, 'properties'):
209
        args.properties = None
210
211
    if not hasattr(args, 'stop_on_error'):
212
        args.stop_on_error = False
213
214
    # Clean file list
215
    if hasattr(args, 'files'):
216
        clean_filelist(args)
217
    else:
218
        args.files = None
219
220
    # set default value for --quiet
221
    if not hasattr(args, 'quiet'):
222
        args.quiet = False
223
224
    # Fix file list - this is needed for aliases - issue#67
225
    # This functions kills the process if a file was not found
226
    fix_filelist(args.files)
227
228
    # Fix properties
229
    fix_properties(args)
230
231
    # Fix attributes (-a/--attribute)
232
    fix_attributes(args)
233
234
    # check for input format
235
    input_format_check(args)
236
237
    # check jobs argument
238
    if args.jobs < 1 or args.jobs > 64:
239
        log.error("Invalid argument in '-j/--jobs'. Please choose something between 1-64!")
240
        sys.exit(ReturnCodes.E_INVALID_ARGUMENTS)
241
242
    return args
243