summaryrefslogtreecommitdiff
path: root/morphlib/cmdline_parse_utils.py
blob: c5e08ec1fd3f1e08e6056babf685808e5220790f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# -*- coding: utf-8 -*-
# Copyright © 2015  Codethink Limited
#
# 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; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.


from itertools import groupby as _groupby
from itertools import takewhile as _takewhile

from cliapp import AppException as _AppException


from .utils import word_join_list as _word_join_list


def _split(iterable, split_token):
    sequence = []
    for token in iterable:
        if token == split_token:
            yield tuple(sequence)
            sequence = []
        else:
            sequence.append(token)
    if sequence:
        yield tuple(sequence)


class SystemsSpecsParseWrongNumber(_AppException):
    def __init__(self, specs, definitions_names):
        self.specs = specs
        self.definitions_names = definitions_names
        msg = 'From expected definition specs {expected};'.format(
                expected=_word_join_list(map(repr, definitions_names)))
        if len(specs) < len(definitions_names):
            missing_spec_names = definitions_names[len(specs):]
            super(SystemsSpecsParseWrongNumber, self).__init__(
                '{msg} missing {missing}'.format(
                    msg=msg,
                    missing=_word_join_list(map(repr, missing_spec_names))))
        else:
            super(SystemsSpecsParseWrongNumber, self).__init__(
                '{msg} {extra} extra specs given'.format(
                    msg=msg,
                    extra=len(specs) - len(definitions_names)))


class SystemsSpecsParseWrongFormat(_AppException):
    def __init__(self, definition_list_name_list, malformed_definition_lists):
        self.definition_list_name_list = definition_list_name_list
        self.malformed_definition_lists = malformed_definition_lists
        errors = []
        for spec, name, i in malformed_definition_lists:
            pre = 'Spec {i} named {name!r}'.format(i=i, name=name)
            if not spec:
                errors.append(pre + ' is empty, want REPO REF SYSTEM...')
            elif len(spec) == 1:
                errors.append(pre + ' missing REF, want REPO REF SYSTEM...')
        super(SystemsSpecsParseWrongFormat, self).__init__(
            'From expected definition specs {expected}:\n\t{errors}'.format(
                expected=_word_join_list(map(repr, definition_list_name_list)),
                errors='\n\t'.join(errors)))


def parse_definition_lists(definition_list_name_list, args):
    specs = tuple(_split(args, '-'))
    if len(specs) != len(definition_list_name_list):
        raise SystemsSpecsParseWrongNumber(specs, definition_list_name_list)

    malformed_definition_lists = []
    specinfo = enumerate(zip(definition_list_name_list, specs), start=1)
    for i, (definition_list_name, definitions_spec) in specinfo:
        if len(definitions_spec) < 2:
            malformed_definition_lists.append(
                (definitions_spec, definition_list_name, i))
    if malformed_definition_lists:
        raise SystemsSpecsParseWrongFormat(definition_list_name_list,
                                           malformed_definition_lists)

    return ((spec[0], spec[1], spec[2:]) for spec in specs)