summaryrefslogtreecommitdiffstats
path: root/testing/mozbase/manifestparser/manifestparser/cli.py
blob: 2fefca33e709d78c17c968e5909fe2f41b41e02a (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#!/usr/bin/env python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

"""
Mozilla universal manifest parser
"""
import os
import sys
from optparse import OptionParser

from .manifestparser import ManifestParser, convert


class ParserError(Exception):
    """error for exceptions while parsing the command line"""


def parse_args(_args):
    """
    parse and return:
    --keys=value (or --key value)
    -tags
    args
    """

    # return values
    _dict = {}
    tags = []
    args = []

    # parse the arguments
    key = None
    for arg in _args:
        if arg.startswith("---"):
            raise ParserError("arguments should start with '-' or '--' only")
        elif arg.startswith("--"):
            if key:
                raise ParserError("Key %s still open" % key)
            key = arg[2:]
            if "=" in key:
                key, value = key.split("=", 1)
                _dict[key] = value
                key = None
                continue
        elif arg.startswith("-"):
            if key:
                raise ParserError("Key %s still open" % key)
            tags.append(arg[1:])
            continue
        else:
            if key:
                _dict[key] = arg
                continue
            args.append(arg)

    # return values
    return (_dict, tags, args)


class CLICommand(object):
    usage = "%prog [options] command"

    def __init__(self, parser):
        self._parser = parser  # master parser

    def parser(self):
        return OptionParser(
            usage=self.usage, description=self.__doc__, add_help_option=False
        )


class Copy(CLICommand):
    usage = "%prog [options] copy manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ..."

    def __call__(self, options, args):
        # parse the arguments
        try:
            kwargs, tags, args = parse_args(args)
        except ParserError as e:
            self._parser.error(str(e))

        # make sure we have some manifests, otherwise it will
        # be quite boring
        if not len(args) == 2:
            HelpCLI(self._parser)(options, ["copy"])
            return

        # read the manifests
        # TODO: should probably ensure these exist here
        manifests = ManifestParser()
        manifests.read(args[0])

        # print the resultant query
        manifests.copy(args[1], None, *tags, **kwargs)


class CreateCLI(CLICommand):
    """
    create a manifest from a list of directories
    """

    usage = "%prog [options] create directory <directory> <...>"

    def parser(self):
        parser = CLICommand.parser(self)
        parser.add_option(
            "-p", "--pattern", dest="pattern", help="glob pattern for files"
        )
        parser.add_option(
            "-i",
            "--ignore",
            dest="ignore",
            default=[],
            action="append",
            help="directories to ignore",
        )
        parser.add_option(
            "-w",
            "--in-place",
            dest="in_place",
            help="Write .ini files in place; filename to write to",
        )
        return parser

    def __call__(self, _options, args):
        parser = self.parser()
        options, args = parser.parse_args(args)

        # need some directories
        if not len(args):
            parser.print_usage()
            return

        # add the directories to the manifest
        for arg in args:
            assert os.path.exists(arg)
            assert os.path.isdir(arg)
            manifest = convert(
                args,
                pattern=options.pattern,
                ignore=options.ignore,
                write=options.in_place,
            )
        if manifest:
            print(manifest)


class WriteCLI(CLICommand):
    """
    write a manifest based on a query
    """

    usage = "%prog [options] write manifest <manifest> -tag1 -tag2 --key1=value1 --key2=value2 ..."

    def __call__(self, options, args):

        # parse the arguments
        try:
            kwargs, tags, args = parse_args(args)
        except ParserError as e:
            self._parser.error(str(e))

        # make sure we have some manifests, otherwise it will
        # be quite boring
        if not args:
            HelpCLI(self._parser)(options, ["write"])
            return

        # read the manifests
        # TODO: should probably ensure these exist here
        manifests = ManifestParser()
        manifests.read(*args)

        # print the resultant query
        manifests.write(global_tags=tags, global_kwargs=kwargs)


class HelpCLI(CLICommand):
    """
    get help on a command
    """

    usage = "%prog [options] help [command]"

    def __call__(self, options, args):
        if len(args) == 1 and args[0] in commands:
            commands[args[0]](self._parser).parser().print_help()
        else:
            self._parser.print_help()
            print("\nCommands:")
            for command in sorted(commands):
                print("  %s : %s" % (command, commands[command].__doc__.strip()))


class UpdateCLI(CLICommand):
    """
    update the tests as listed in a manifest from a directory
    """

    usage = "%prog [options] update manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ..."

    def __call__(self, options, args):
        # parse the arguments
        try:
            kwargs, tags, args = parse_args(args)
        except ParserError as e:
            self._parser.error(str(e))

        # make sure we have some manifests, otherwise it will
        # be quite boring
        if not len(args) == 2:
            HelpCLI(self._parser)(options, ["update"])
            return

        # read the manifests
        # TODO: should probably ensure these exist here
        manifests = ManifestParser()
        manifests.read(args[0])

        # print the resultant query
        manifests.update(args[1], None, *tags, **kwargs)


# command -> class mapping
commands = {
    "create": CreateCLI,
    "help": HelpCLI,
    "update": UpdateCLI,
    "write": WriteCLI,
}


def main(args=sys.argv[1:]):
    """console_script entry point"""

    # set up an option parser
    usage = "%prog [options] [command] ..."
    description = "%s. Use `help` to display commands" % __doc__.strip()
    parser = OptionParser(usage=usage, description=description)
    parser.add_option(
        "-s",
        "--strict",
        dest="strict",
        action="store_true",
        default=False,
        help="adhere strictly to errors",
    )
    parser.disable_interspersed_args()

    options, args = parser.parse_args(args)

    if not args:
        HelpCLI(parser)(options, args)
        parser.exit()

    # get the command
    command = args[0]
    if command not in commands:
        parser.error(
            "Command must be one of %s (you gave '%s')"
            % (", ".join(sorted(commands.keys())), command)
        )

    handler = commands[command](parser)
    handler(options, args[1:])


if __name__ == "__main__":
    main()