[go: up one dir, main page]

File: cli.py

package info (click to toggle)
kiwi 9.24.56-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 6,844 kB
  • sloc: python: 58,147; sh: 3,261; xml: 2,919; makefile: 304; ansic: 132
file content (332 lines) | stat: -rw-r--r-- 11,380 bytes parent folder | download
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# Copyright (c) 2015 SUSE Linux GmbH.  All rights reserved.
#
# This file is part of kiwi.
#
# kiwi 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, either version 3 of the License, or
# (at your option) any later version.
#
# kiwi 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 kiwi.  If not, see <http://www.gnu.org/licenses/>
#
"""
usage: kiwi-ng -h | --help
       kiwi-ng [--profile=<name>...]
               [--temp-dir=<directory>]
               [--target-arch=<name>]
               [--type=<build_type>]
               [--logfile=<filename>]
               [--logsocket=<socketfile>]
               [--loglevel=<number>]
               [--debug]
               [--debug-run-scripts-in-screen]
               [--color-output]
               [--config=<configfile>]
               [--kiwi-file=<kiwifile>]
           image <command> [<args>...]
       kiwi-ng [--logfile=<filename>]
               [--logsocket=<socketfile>]
               [--loglevel=<number>]
               [--debug]
               [--debug-run-scripts-in-screen]
               [--color-output]
               [--config=<configfile>]
           result <command> [<args>...]
       kiwi-ng [--profile=<name>...]
               [--shared-cache-dir=<directory>]
               [--temp-dir=<directory>]
               [--target-arch=<name>]
               [--type=<build_type>]
               [--logfile=<filename>]
               [--logsocket=<socketfile>]
               [--loglevel=<number>]
               [--debug]
               [--debug-run-scripts-in-screen]
               [--color-output]
               [--config=<configfile>]
               [--kiwi-file=<kiwifile>]
           system <command> [<args>...]
       kiwi-ng compat <legacy_args>...
       kiwi-ng --compat <legacy_args>...
       kiwi-ng -v | --version
       kiwi-ng help

global options:
    --color-output
        use colors for warning and error messages
    --config=<configfile>
        use specified runtime configuration file. If
        not specified the runtime configuration is looked
        up at ~/.config/kiwi/config.yml or /etc/kiwi.yml
    --logfile=<filename>
        create a log file containing all log information including
        debug information even if this is was not requested by the
        debug switch. The special call: '--logfile stdout' sends all
        information to standard out instead of writing to a file
    --logsocket=<socketfile>
        send log data to the given Unix Domain socket in the same
        format as with --logfile
    --loglevel=<number>
        specify logging level as number. Details about the
        available log levels can be found at:
        https://docs.python.org/3/library/logging.html#logging-levels
        Setting a log level causes all message >= level to be
        displayed.
    --debug
        print debug information, same as: '--loglevel 10'
    --debug-run-scripts-in-screen
        run scripts called by kiwi in a screen session
    -v --version
        show program version
    help
        show manual page

global options for services: image, system
    --profile=<name>
        profile name, multiple profiles can be selected by passing
        this option multiple times
    --shared-cache-dir=<directory>
        specify an alternative shared cache directory. The directory
        is shared via bind mount between the build host and image
        root system and contains information about package repositories
        and their cache and meta data.
    --temp-dir=<directory>
        specify an alternative base temporary directory. The
        provided path is used as base directory to store temporary
        files and directories. By default /var/tmp is used.
    --type=<build_type>
        image build type. If not set the default XML specified
        build type will be used
    --kiwi-file=<kiwifile>
        Basename of kiwi file which contains the main image
        configuration elements. If not specified kiwi searches for
        a file named config.xml or a file matching *.kiwi

global options for services: image, system
    --target-arch=<name>
        set the image architecture. By default the host architecture is
        used as the image architecture. If the specified architecture name
        does not match the host architecture and is therefore requesting
        a cross architecture image build, it's important to understand that
        for this process to work a preparatory step to support the image
        architecture and binary format on the building host is required
        and not a responsibility of kiwi.
"""
import logging
import sys
import os
import pkg_resources
from docopt import docopt

# project
from kiwi.exceptions import (
    KiwiUnknownServiceName,
    KiwiCommandNotLoaded,
    KiwiLoadCommandUndefined,
    KiwiCompatError
)
from kiwi.path import Path
from kiwi.version import __version__
from kiwi.help import Help
from kiwi.defaults import Defaults

log = logging.getLogger('kiwi')


class Cli:
    """
    **Implements the main command line interface**

    An instance of the Cli class builds the entry point for the
    application and implements methods to load further command plugins
    which itself provides their own command line interface
    """
    def __init__(self):
        self.all_args = docopt(
            __doc__,
            version='KIWI (next generation) version ' + __version__,
            options_first=True
        )
        self.command_args = self.all_args['<args>']
        self.command_loaded = None

    def show_and_exit_on_help_request(self):
        """
        Execute man to show the selected manual page
        """
        if self.all_args['help']:
            manual = Help()
            manual.show('kiwi')
            sys.exit(0)

    def get_servicename(self):
        """
        Extract service name from argument parse result

        :return: service name

        :rtype: str
        """
        if self.all_args.get('image') is True:
            return 'image'
        elif self.all_args.get('system') is True:
            return 'system'
        elif self.all_args.get('result') is True:
            return 'result'
        elif self.all_args.get('--compat') is True:
            return 'compat'
        elif self.all_args.get('compat') is True:
            return 'compat'
        else:
            raise KiwiUnknownServiceName(
                'Unknown/Invalid Servicename'
            )

    def invoke_kiwicompat(self, compat_args):
        """
        Execute kiwicompat with provided legacy KIWI command line arguments

        Example:

        .. code:: python

            invoke_kiwicompat(
                '--build', 'description', '--type', 'vmx',
                '-d', 'destination'
            )

        :param list compat_args: legacy kiwi command arguments
        """
        kiwicompat = Path.which('kiwicompat', access_mode=os.X_OK)
        try:
            os.execvp(kiwicompat, ['kiwicompat'] + compat_args)
        except Exception as e:
            raise KiwiCompatError(
                '%s: %s' % (type(e).__name__, format(e))
            )

    def get_command(self):
        """
        Extract selected command name

        :return: command name
        :rtype: str
        """
        return self.all_args['<command>']

    def get_command_args(self):
        """
        Extract argument dict for selected command

        :return:
            Contains dictionary of command arguments

            .. code:: python

                {
                    '--command-option': 'value'
                }

        :rtype: dict
        """
        return self._load_command_args()

    def get_global_args(self):
        """
        Extract argument dict for global arguments

        :return:
            Contains dictionary of global arguments

            .. code:: python

                {
                    '--global-option': 'value'
                }

        :rtype: dict
        """
        result = {}
        for arg, value in list(self.all_args.items()):
            if not arg == '<command>' and not arg == '<args>':
                if arg == '--type' and value == 'vmx':
                    log.warning(
                        'vmx type is now a subset of oem, --type set to oem'
                    )
                    value = 'oem'
                if arg == '--shared-cache-dir' and not value:
                    value = os.sep + Defaults.get_shared_cache_location()
                if arg == '--shared-cache-dir' and value:
                    Defaults.set_shared_cache_location(value)
                if arg == '--temp-dir' and not value:
                    value = Defaults.get_temp_location()
                if arg == '--temp-dir' and value:
                    Defaults.set_temp_location(value)
                if arg == '--target-arch' and value:
                    Defaults.set_platform_name(value)
                if arg == '--config' and value:  # pragma: no cover
                    Defaults.set_custom_runtime_config_file(value)
                result[arg] = value
        return result

    def load_command(self):
        """
        Loads task class plugin according to service and command name

        :return: loaded task module

        :rtype: object
        """
        discovered_tasks = {
            entry_point.name: entry_point.load()
            for entry_point in pkg_resources.iter_entry_points('kiwi.tasks')
        }
        service = self.get_servicename()
        command = self.get_command()

        if service == 'compat':
            compat_arguments = self.all_args['<legacy_args>']
            if '--' in compat_arguments:
                compat_arguments.remove('--')
            return self.invoke_kiwicompat(compat_arguments)

        if not command:
            raise KiwiLoadCommandUndefined(
                'No command specified for {0} service'.format(service)
            )

        self.command_loaded = discovered_tasks.get(
            service + '_' + command
        )
        if not self.command_loaded:
            prefix = 'usage:'
            discovered_tasks_for_service = ''
            for task in discovered_tasks:
                if task.startswith(service):
                    discovered_tasks_for_service += '{0} kiwi-ng {1}\n'.format(
                        prefix, task.replace('_', ' ')
                    )
                    prefix = '      '
            raise KiwiCommandNotLoaded(
                'Command "{0}" not found\n\n{1}'.format(
                    command, discovered_tasks_for_service
                )
            )
        return self.command_loaded

    def _load_command_args(self):
        try:
            argv = [
                self.get_servicename(), self.get_command()
            ] + self.command_args
            return docopt(self.command_loaded.__doc__, argv=argv)
        except Exception:
            raise KiwiCommandNotLoaded(
                '%s command not loaded' % self.get_command()
            )