Exemple #1
0
    def do_run(self, args, user_args):
        config_settings = configparser.ConfigParser()
        configfile = args.configfile or ConfigFile.ALL

        name_list = args.name.split(".", 1)

        if len(name_list) != 2:
            log.die(
                'missing key, please invoke as: west config '
                '<section>.<key>',
                exit_code=3)

        section = name_list[0]
        key = name_list[1]

        if args.value is None:
            configuration.read_config(configfile, config_settings)
            value = config_settings.get(section, key, fallback=None)
            if value is not None:
                log.inf(value)
        else:
            if configfile == ConfigFile.ALL:
                # No file given, thus writing defaults to LOCAL
                configfile = ConfigFile.LOCAL
            configuration.update_config(section, key, args.value, configfile)
Exemple #2
0
 def list(self, args):
     cfg = configparser.ConfigParser()
     what = args.configfile or ALL
     read_config(configfile=what, config=cfg)
     for s in cfg.sections():
         for k, v in cfg[s].items():
             log.inf(f'{s}.{k}={v}')
Exemple #3
0
def test_init_with_manifest_filename(repos_tmpdir):
    # Test 'west init --mf' on a normal repo

    west_tmpdir = repos_tmpdir / 'workspace'
    manifest = repos_tmpdir / 'repos' / 'zephyr'

    with open(manifest / 'west.yml', 'r') as f:
        manifest_data = f.read()

    # also creates a west.yml with a syntax error to verify west doesn't even
    # try to load the file
    add_commit(str(manifest),
               'rename manifest',
               files={
                   'west.yml': '[',
                   'project.yml': manifest_data
               })

    # syntax error
    with pytest.raises(subprocess.CalledProcessError):
        cmd(f'init -m "{manifest}" "{west_tmpdir}"')
    shutil.move(west_tmpdir, repos_tmpdir / 'workspace-syntaxerror')

    # success
    cmd(f'init -m "{manifest}" --mf project.yml "{west_tmpdir}"')
    west_tmpdir.chdir()
    config.read_config()
    cmd('update')
Exemple #4
0
    def run(self, argv):
        # Run the command-line application with argument list 'argv'.

        # See if we're in a workspace. It's fine if we're not.
        # Note that this falls back on searching from ZEPHYR_BASE
        # if the current directory isn't inside a west workspace.
        try:
            self.topdir = west_topdir()
        except WestNotFound:
            pass

        # Read the configuration files. We need this to get
        # manifest.path to parse the manifest, etc.
        #
        # TODO: re-work to avoid global state (#149).
        config.read_config(topdir=self.topdir)

        # Set self.manifest and self.extensions.
        self.load_manifest()
        self.load_extension_specs()

        # Set up initial argument parsers. This requires knowing
        # self.extensions, so it can't happen before now.
        self.setup_parsers()

        # OK, we are all set. Run the command.
        self.run_command(argv)
Exemple #5
0
 def list(self, args):
     cfg = configparser.ConfigParser()
     what = args.configfile or ALL
     read_config(configfile=what, config=cfg)
     for s in cfg.sections():
         for k, v in cfg[s].items():
             log.inf('{}.{}={}'.format(s, k, v))
Exemple #6
0
def main(argv=None):
    # Makes ANSI color escapes work on Windows, and strips them when
    # stdout/stderr isn't a terminal
    colorama.init()

    # See if we're in an installation.
    try:
        topdir = west_topdir()
    except WestNotFound:
        topdir = None

    # Read the configuration files before looking for extensions.
    # We need this to find the manifest path in order to load extensions.
    config.read_config()

    # Load any extension command specs if we're in an installation.
    if topdir:
        try:
            extensions = get_extension_commands()
        except (MalformedConfig, FileNotFoundError):
            extensions = {}
    else:
        extensions = {}

    if argv is None:
        argv = sys.argv[1:]
    args, unknown = parse_args(argv, extensions, topdir)

    for_stack_trace = 'run as "west -v {}" for a stack trace'.format(
        quote_sh_list(argv))
    try:
        args.handler(args, unknown)
    except KeyboardInterrupt:
        sys.exit(0)
    except CalledProcessError as cpe:
        log.err('command exited with status {}: {}'.format(
            cpe.args[0], quote_sh_list(cpe.args[1])))
        if args.verbose:
            traceback.print_exc()
        else:
            log.inf(for_stack_trace)
        sys.exit(cpe.returncode)
    except ExtensionCommandError as ece:
        log.err(
            'extension command', args.command,
            'was improperly defined and could not be run{}'.format(
                ': ' + ece.hint if ece.hint else ''))
        if args.verbose:
            traceback.print_exc()
        else:
            log.inf(for_stack_trace)
        sys.exit(ece.returncode)
    except CommandContextError as cce:
        log.err('command', args.command, 'cannot be run in this context:',
                *cce.args)
        sys.exit(cce.returncode)
    except CommandError as ce:
        sys.exit(ce.returncode)
Exemple #7
0
def main(argv=None):
    # Makes ANSI color escapes work on Windows, and strips them when
    # stdout/stderr isn't a terminal
    colorama.init()

    # See if we're in an installation.
    try:
        topdir = west_topdir()
    except WestNotFound:
        topdir = None

    # Read the configuration files before looking for extensions.
    # We need this to find the manifest path in order to load extensions.
    config.read_config()

    # Load any extension command specs if we're in an installation.
    if topdir:
        try:
            extensions = get_extension_commands()
        except (MalformedConfig, FileNotFoundError):
            extensions = {}
    else:
        extensions = {}

    if argv is None:
        argv = sys.argv[1:]
    args, unknown = parse_args(argv, extensions, topdir)

    try:
        args.handler(args, unknown)
    except KeyboardInterrupt:
        sys.exit(0)
    except CalledProcessError as cpe:
        log.err('command exited with status {}: {}'.format(
            cpe.returncode, quote_sh_list(cpe.cmd)))
        if args.verbose:
            traceback.print_exc()
        sys.exit(cpe.returncode)
    except ExtensionCommandError as ece:
        msg = 'extension command "{}" could not be run{}.'.format(
            args.command, ': ' + ece.hint if ece.hint else '')
        if args.verbose:
            log.err(msg)
            traceback.print_exc()
        else:
            log.err(msg, 'See {} for a traceback.'.format(dump_traceback()))
        sys.exit(ece.returncode)
    except CommandContextError as cce:
        log.err('command', args.command, 'cannot be run in this context:',
                *cce.args)
        log.err('see {} for a traceback.'.format(dump_traceback()))
        sys.exit(cce.returncode)
    except CommandError as ce:
        # No need to dump_traceback() here. The command is responsible
        # for logging its own errors.
        sys.exit(ce.returncode)
Exemple #8
0
 def read(self, args):
     section, key = self._sk(args)
     cfg = configparser.ConfigParser()
     read_config(configfile=args.configfile or ALL, config=cfg)
     value = cfg.get(section, key, fallback=None)
     if value is not None:
         log.inf(value)
     else:
         log.dbg(f'{args.name} is unset')
         raise CommandError(returncode=1)
Exemple #9
0
def config_file_project_setup(tmpdir):
    tmpdir.join('.west/.west_topdir').ensure()
    tmpdir.join('.west/config').write('''
[manifest]
path = manifestproject
''')

    # Switch to the top-level West installation directory
    tmpdir.chdir()

    config.read_config()

    return tmpdir
Exemple #10
0
def west_init_tmpdir(repos_tmpdir):
    '''Fixture for a tmpdir with 'remote' repositories and 'west init' run.

    Uses the remote repositories from the repos_tmpdir fixture to
    create a west workspace using west init.

    The contents of the west workspace aren't checked at all.
    This is left up to the test cases.

    The directory that 'west init' created is returned as a
    py.path.local, with the current working directory set there.'''
    west_tmpdir = repos_tmpdir / 'workspace'
    manifest = repos_tmpdir / 'repos' / 'zephyr'
    cmd(f'init -m "{manifest}" "{west_tmpdir}"')
    west_tmpdir.chdir()
    config.read_config()
    return west_tmpdir
Exemple #11
0
def _mpath(cp=None, topdir=None):
    # Return the value of the manifest.path configuration option
    # in *cp*, a ConfigParser. If not given, create a new one and
    # load configuration options with the given *topdir* as west
    # installation root.
    #
    # TODO: write a cfg.get(section, key)
    # wrapper, with friends for update and delete, to avoid
    # requiring this boilerplate.
    if cp is None:
        cp = cfg._configparser()
    cfg.read_config(configfile=cfg.ConfigFile.LOCAL, config=cp, topdir=topdir)

    try:
        return cp.get('manifest', 'path')
    except (configparser.NoOptionError, configparser.NoSectionError) as e:
        raise MalformedConfig('no "manifest.path" config option is set') from e
Exemple #12
0
def west_init_tmpdir(repos_tmpdir):
    '''Fixture for a tmpdir with 'remote' repositories and 'west init' run.

    Uses the remote repositories from the repos_tmpdir fixture to
    create a west installation using the system bootstrapper's init
    command.

    The contents of the west installation aren't checked at all.
    This is left up to the test cases.

    The directory that 'west init' created is returned as a
    py.path.local, with the current working directory set there.'''
    west_tmpdir = repos_tmpdir.join('west_installation')
    cmd('init -m "{}" "{}"'.format(str(repos_tmpdir.join('repos', 'zephyr')),
                                   str(west_tmpdir)))
    west_tmpdir.chdir()
    config.read_config()
    return west_tmpdir
Exemple #13
0
def test_init_local_with_manifest_filename(repos_tmpdir):
    # Test 'west init --mf -l' on a local repo

    manifest = repos_tmpdir / 'repos' / 'zephyr'
    workspace = repos_tmpdir / 'workspace'
    zephyr_install_dir = workspace / 'zephyr'

    # Do a local clone of manifest repo
    clone(str(manifest), str(zephyr_install_dir))
    os.rename(str(zephyr_install_dir / 'west.yml'),
              str(zephyr_install_dir / 'project.yml'))

    # fails because west.yml is missing
    with pytest.raises(subprocess.CalledProcessError):
        cmd(f'init -l "{zephyr_install_dir}"')

    # create a manifest with a syntax error so we can test if it's being parsed
    with open(zephyr_install_dir / 'west.yml', 'w') as f:
        f.write('[')

    cwd = os.getcwd()
    cmd(f'init -l "{zephyr_install_dir}"')

    # init with a local manifest doesn't parse the file, so let's access it
    workspace.chdir()
    with pytest.raises(subprocess.CalledProcessError):
        cmd('list')

    os.chdir(cwd)
    shutil.move(workspace / '.west', workspace / '.west-syntaxerror')

    # success
    cmd(f'init --mf project.yml -l "{zephyr_install_dir}"')
    workspace.chdir()
    config.read_config()
    cmd('update')
Exemple #14
0
def main(argv=None):
    # Silence validation errors from pykwalify, which are logged at
    # logging.ERROR level. We want to handle those ourselves as
    # needed.
    logging.getLogger('pykwalify').setLevel(logging.CRITICAL)

    # Makes ANSI color escapes work on Windows, and strips them when
    # stdout/stderr isn't a terminal
    colorama.init()

    # See if we're in an installation.
    try:
        topdir = west_topdir()
    except WestNotFound:
        topdir = None

    # Read the configuration files before looking for extensions.
    # We need this to find the manifest path in order to load extensions.
    config.read_config()

    # Parse the manifest and create extension command thunks. We'll
    # pass the saved manifest around so it doesn't have to be
    # re-parsed.
    if topdir:
        try:
            manifest = Manifest.from_file()
            extensions = get_extension_commands(manifest)
        except (MalformedManifest, MalformedConfig, FileNotFoundError):
            manifest = None
            extensions = None
    else:
        manifest = None
        extensions = {}

    if argv is None:
        argv = sys.argv[1:]
    args, unknown = parse_args(argv, extensions, topdir, manifest)

    try:
        args.handler(args, unknown)
    except KeyboardInterrupt:
        sys.exit(0)
    except CalledProcessError as cpe:
        log.err('command exited with status {}: {}'.format(
            cpe.returncode, quote_sh_list(cpe.cmd)))
        if args.verbose:
            traceback.print_exc()
        sys.exit(cpe.returncode)
    except ExtensionCommandError as ece:
        msg = 'extension command "{}" could not be run{}.'.format(
            args.command, ': ' + ece.hint if ece.hint else '')
        if args.verbose:
            log.err(msg)
            traceback.print_exc()
        else:
            log.err(msg, 'See {} for a traceback.'.format(dump_traceback()))
        sys.exit(ece.returncode)
    except CommandContextError as cce:
        log.err('command', args.command, 'cannot be run in this context:',
                *cce.args)
        log.err('see {} for a traceback.'.format(dump_traceback()))
        sys.exit(cce.returncode)
    except CommandError as ce:
        # No need to dump_traceback() here. The command is responsible
        # for logging its own errors.
        sys.exit(ce.returncode)
    except (MalformedManifest, MalformedConfig) as malformed:
        log.die("can't load west manifest:", malformed)
Exemple #15
0
def test_extension_command_duplicate(repos_tmpdir):
    # Test to ensure that in case to subprojects introduces same command, it
    # will print a warning.
    rr = repos_tmpdir.join('repos')
    remote_kconfiglib = str(rr.join('Kconfiglib'))
    remote_zephyr = str(rr.join('zephyr'))
    remote_west = str(rr.join('west'))

    add_commit(remote_zephyr,
               'test added extension command',
               files={
                   'west.yml':
                   textwrap.dedent('''\
                      west:
                        url: file://{west}
                      manifest:
                        defaults:
                          remote: test-local

                        remotes:
                          - name: test-local
                            url-base: file://{rr}

                        projects:
                          - name: Kconfiglib
                            revision: zephyr
                            path: subdir/Kconfiglib
                            west-commands: scripts/west-commands.yml
                          - name: net-tools
                            west-commands: scripts/west-commands.yml
                        self:
                          path: zephyr
                      '''.format(west=remote_west, rr=str(rr)))
               })

    # Initialize the net-tools repository.
    add_commit(remote_kconfiglib,
               'add west commands',
               files={
                   'scripts/west-commands.yml':
                   textwrap.dedent('''\
                      west-commands:
                        - file: scripts/test.py
                          commands:
                            - name: test
                              class: Test
                      '''),
                   'scripts/test.py':
                   textwrap.dedent('''\
                      from west.commands import WestCommand
                      class Test(WestCommand):
                          def __init__(self):
                              super(Test, self).__init__(
                                  'test',
                                  'test application',
                                  '')
                          def do_add_parser(self, parser_adder):
                              parser = parser_adder.add_parser(self.name)
                              return parser
                          def do_run(self, args, ignored):
                              print('Testing kconfig test command')
                      '''),
               })
    west_tmpdir = repos_tmpdir.join('west_installation')
    cmd('init -m "{}" "{}"'.format(str(repos_tmpdir.join('repos', 'zephyr')),
                                   str(west_tmpdir)))
    west_tmpdir.chdir()
    config.read_config()
    cmd('update')

    actual = cmd('test', stderr=subprocess.STDOUT)
    warning = 'WARNING: ignoring project net-tools extension command "test";'\
              ' command "test" already defined as extension command\n'
    command_out = 'Testing kconfig test command\n'

    assert actual == warning + command_out
Exemple #16
0
def test_extension_command_multiproject(repos_tmpdir):
    # Test to ensure that multiple projects can define extension commands and
    # that those are correctly presented and executed.
    rr = repos_tmpdir.join('repos')
    remote_kconfiglib = str(rr.join('Kconfiglib'))
    remote_zephyr = str(rr.join('zephyr'))
    remote_west = str(rr.join('west'))

    # Update the manifest to specify extension commands in Kconfiglib.
    add_commit(remote_zephyr,
               'test added extension command',
               files={
                   'west.yml':
                   textwrap.dedent('''\
                      west:
                        url: file://{west}
                      manifest:
                        defaults:
                          remote: test-local

                        remotes:
                          - name: test-local
                            url-base: file://{rr}

                        projects:
                          - name: Kconfiglib
                            revision: zephyr
                            path: subdir/Kconfiglib
                            west-commands: scripts/west-commands.yml
                          - name: net-tools
                            west-commands: scripts/west-commands.yml
                        self:
                          path: zephyr
                      '''.format(west=remote_west, rr=str(rr)))
               })

    # Add an extension command to the Kconfiglib remote.
    add_commit(remote_kconfiglib,
               'add west commands',
               files={
                   'scripts/west-commands.yml':
                   textwrap.dedent('''\
                      west-commands:
                        - file: scripts/test.py
                          commands:
                            - name: kconfigtest
                              class: Test
                      '''),
                   'scripts/test.py':
                   textwrap.dedent('''\
                      from west.commands import WestCommand
                      class Test(WestCommand):
                          def __init__(self):
                              super(Test, self).__init__(
                                  'kconfigtest',
                                  'Kconfig test application',
                                  '')
                          def do_add_parser(self, parser_adder):
                              parser = parser_adder.add_parser(self.name)
                              return parser
                          def do_run(self, args, ignored):
                              print('Testing kconfig test')
                      '''),
               })
    west_tmpdir = repos_tmpdir.join('west_installation')
    cmd('init -m "{}" "{}"'.format(str(repos_tmpdir.join('repos', 'zephyr')),
                                   str(west_tmpdir)))
    west_tmpdir.chdir()
    config.read_config()
    cmd('update')

    help_text = cmd('-h')
    expected = textwrap.dedent('''\
        commands from project at "subdir/Kconfiglib":
          kconfigtest:          (no help provided; try "west kconfigtest -h")

        commands from project at "net-tools":
          test:                 test-help
        ''')

    assert expected in help_text

    actual = cmd('test')
    assert actual == 'Testing test command 1\n'

    actual = cmd('kconfigtest')
    assert actual == 'Testing kconfig test\n'
Exemple #17
0
def test_extension_command_multiproject(repos_tmpdir):
    # Test to ensure that multiple projects can define extension commands and
    # that those are correctly presented and executed.
    rr = repos_tmpdir.join('repos')
    remote_kconfiglib = str(rr.join('Kconfiglib'))
    remote_zephyr = str(rr.join('zephyr'))
    remote_west = str(rr.join('west'))

    # Update the manifest to specify extension commands in Kconfiglib.
    # This removes tagged_repo, but we're not using it, so that's fine.
    add_commit(remote_zephyr,
               'test added extension command',
               files={
                   'west.yml':
                   textwrap.dedent(f'''\
                      west:
                        url: file://{remote_west}
                      manifest:
                        defaults:
                          remote: test-local

                        remotes:
                          - name: test-local
                            url-base: file://{rr}

                        projects:
                          - name: Kconfiglib
                            revision: zephyr
                            path: subdir/Kconfiglib
                            west-commands: scripts/west-commands.yml
                          - name: net-tools
                            west-commands: scripts/west-commands.yml
                        self:
                          path: zephyr
                      ''')
               })

    # Add an extension command to the Kconfiglib remote.
    add_commit(remote_kconfiglib,
               'add west commands',
               files={
                   'scripts/west-commands.yml':
                   textwrap.dedent('''\
                      west-commands:
                        - file: scripts/test.py
                          commands:
                            - name: kconfigtest
                              class: Test
                      '''),
                   'scripts/test.py':
                   textwrap.dedent('''\
                      from west.commands import WestCommand
                      class Test(WestCommand):
                          def __init__(self):
                              super(Test, self).__init__(
                                  'kconfigtest',
                                  'Kconfig test application',
                                  '')
                          def do_add_parser(self, parser_adder):
                              parser = parser_adder.add_parser(self.name)
                              return parser
                          def do_run(self, args, ignored):
                              print('Testing kconfig test')
                      '''),
               })
    west_tmpdir = repos_tmpdir / 'workspace'
    zephyr = repos_tmpdir / 'repos' / 'zephyr'
    cmd(f'init -m "{zephyr}" "{west_tmpdir}"')
    west_tmpdir.chdir()
    config.read_config()
    cmd('update')

    # The newline shenanigans are for Windows.
    help_text = '\n'.join(cmd('-h').splitlines())
    expected = '\n'.join([
        'extension commands from project Kconfiglib (path: subdir/Kconfiglib):',  # noqa: E501
        '  kconfigtest:          (no help provided; try "west kconfigtest -h")',  # noqa: E501
        '',
        'extension commands from project net-tools (path: net-tools):',
        '  test-extension:       test-extension-help'
    ])
    assert expected in help_text, help_text

    actual = cmd('test-extension')
    assert actual.rstrip() == 'Testing test command 1'

    actual = cmd('kconfigtest')
    assert actual.rstrip() == 'Testing kconfig test'
Exemple #18
0
def test_extension_command_duplicate(repos_tmpdir):
    # Test to ensure that in case to subprojects introduces same command, it
    # will print a warning.
    rr = repos_tmpdir.join('repos')
    remote_kconfiglib = str(rr.join('Kconfiglib'))
    remote_zephyr = str(rr.join('zephyr'))
    remote_west = str(rr.join('west'))

    # This removes tagged_repo, but we're not using it, so that's fine.
    add_commit(remote_zephyr,
               'test added extension command',
               files={
                   'west.yml':
                   textwrap.dedent(f'''\
                      west:
                        url: file://{remote_west}
                      manifest:
                        defaults:
                          remote: test-local

                        remotes:
                          - name: test-local
                            url-base: file://{rr}

                        projects:
                          - name: Kconfiglib
                            revision: zephyr
                            path: subdir/Kconfiglib
                            west-commands: scripts/west-commands.yml
                          - name: net-tools
                            west-commands: scripts/west-commands.yml
                        self:
                          path: zephyr
                      ''')
               })

    # Initialize the net-tools repository.
    add_commit(remote_kconfiglib,
               'add west commands',
               files={
                   'scripts/west-commands.yml':
                   textwrap.dedent('''\
                      west-commands:
                        - file: scripts/test.py
                          commands:
                            - name: test-extension
                              class: Test
                      '''),
                   'scripts/test.py':
                   textwrap.dedent('''\
                      from west.commands import WestCommand
                      class Test(WestCommand):
                          def __init__(self):
                              super(Test, self).__init__(
                                  'test-extension',
                                  'test application',
                                  '')
                          def do_add_parser(self, parser_adder):
                              parser = parser_adder.add_parser(self.name)
                              return parser
                          def do_run(self, args, ignored):
                              print('Testing kconfig test command')
                      '''),
               })
    west_tmpdir = repos_tmpdir / 'workspace'
    zephyr = repos_tmpdir / 'repos' / 'zephyr'
    cmd(f'init -m "{zephyr}" "{west_tmpdir}"')
    west_tmpdir.chdir()
    config.read_config()
    cmd('update')

    actual = cmd('test-extension', stderr=subprocess.STDOUT).splitlines()
    expected = [
        'WARNING: ignoring project net-tools extension command "test-extension"; command "test-extension" is already defined as extension command',  # noqa: E501
        'Testing kconfig test command',
    ]

    assert actual == expected
Exemple #19
0
def main(argv=None):
    # Makes ANSI color escapes work on Windows, and strips them when
    # stdout/stderr isn't a terminal
    colorama.init()

    # Read the configuration files
    config.read_config()

    # Load any extension command specs. If the config file isn't
    # fully set up yet or the west.yml cannot be found, ignore the error.
    # This allows west init to work properly.
    try:
        extensions = get_extension_commands()
    except (MalformedConfig, FileNotFoundError):
        extensions = {}

    if argv is None:
        argv = sys.argv[1:]
    args, unknown = parse_args(argv, extensions)

    for_stack_trace = 'run as "west -v {}" for a stack trace'.format(
        quote_sh_list(argv))
    try:
        args.handler(args, unknown)
    except WestUpdated:
        # West has been automatically updated. Restart ourselves to run the
        # latest version, with the same arguments that we were given.
        # Treat the Python script as an executable. This works because on
        # Unix the script created by pip has a shebang and on Windows it is
        # actually a binary executable
        log.dbg("sys.argv[0]:\"{}\" argv:\"{}\"".format(sys.argv[0], argv))
        # Use Popen + exit instead of execv due to the asynchronous nature of
        # execv on Windows, where it creates a new process with a different
        # pid that executes in parallel to the original one instead of
        # replacing it as it does on UNIX
        # https://bugs.python.org/issue9148
        # https://bugs.python.org/issue19124
        try:
            proc = Popen([sys.argv[0]] + argv)
            proc.communicate()
        except KeyboardInterrupt:
            sys.exit(0)
        log.dbg('proc.returncode: {}'.format(proc.returncode))
        sys.exit(errno.EIO if proc.returncode is None else proc.returncode)
    except KeyboardInterrupt:
        sys.exit(0)
    except CalledProcessError as cpe:
        log.err('command exited with status {}: {}'.format(
            cpe.args[0], quote_sh_list(cpe.args[1])))
        if args.verbose:
            traceback.print_exc()
        else:
            log.inf(for_stack_trace)
        sys.exit(cpe.returncode)
    except ExtensionCommandError as ece:
        log.err(
            'extension command', args.command,
            'was improperly defined and could not be run{}'.format(
                ': ' + ece.hint if ece.hint else ''))
        if args.verbose:
            traceback.print_exc()
        else:
            log.inf(for_stack_trace)
        sys.exit(ece.returncode)
    except CommandContextError as cce:
        log.err('command', args.command, 'cannot be run in this context:',
                *cce.args)
        sys.exit(cce.returncode)
    except CommandError as ce:
        sys.exit(ce.returncode)
Exemple #20
0
def cfg(f=ALL, topdir=None):
    # Load a fresh configuration object at the given level, and return it.
    cp = configparser.ConfigParser(allow_no_value=True)
    config.read_config(configfile=f, config=cp, topdir=topdir)
    return cp
Exemple #21
0
def main(argv=None):
    # Silence validation errors from pykwalify, which are logged at
    # logging.ERROR level. We want to handle those ourselves as
    # needed.
    logging.getLogger('pykwalify').setLevel(logging.CRITICAL)

    # Makes ANSI color escapes work on Windows, and strips them when
    # stdout/stderr isn't a terminal
    colorama.init()

    # See if we're in an installation.
    try:
        topdir = west_topdir()
    except WestNotFound:
        topdir = None

    # Read the configuration files before looking for extensions.
    # We need this to find the manifest path in order to load extensions.
    config.read_config(topdir=topdir)

    # Parse the manifest and create extension command thunks. We'll
    # pass the saved manifest around so it doesn't have to be
    # re-parsed.
    mve = None
    if topdir:
        try:
            manifest = Manifest.from_file(topdir=topdir)
            extensions = get_extension_commands(manifest)
        except (MalformedManifest, MalformedConfig, FileNotFoundError,
                ManifestVersionError) as e:
            manifest = None
            extensions = None
            if isinstance(e, ManifestVersionError):
                mve = e
    else:
        manifest = None
        extensions = {}

    # Create the initial set of parsers. We'll need to re-create these
    # if we're running an extension command. Register extensions with
    # the parser.
    if argv is None:
        argv = sys.argv[1:]
    west_parser, subparser_gen = _make_parsers()
    west_parser.west_extensions = extensions
    west_parser.mve = mve

    # Cache the parser in the global Help instance. Dirty, but it
    # needs this data as its parser attribute is not the parent
    # parser, but the return value of a subparser_gen.
    BUILTIN_COMMANDS['help'].west_parser = west_parser

    # Add sub-parsers for the built-in commands.
    for command in BUILTIN_COMMANDS.values():
        command.add_parser(subparser_gen)

    # Add stub parsers for extensions.
    #
    # These just reserve the names of each extension. The real parser
    # for each extension can't be added until we import the
    # extension's code, which we won't do unless parse_known_args()
    # says to run that extension.
    extensions_by_name = {}
    if extensions:
        for path, specs in extensions.items():
            for spec in specs:
                subparser_gen.add_parser(spec.name, add_help=False)
                extensions_by_name[spec.name] = spec

    # Parse arguments for the first time. We'll need to do this again
    # if we're running an extension.
    args, unknown = west_parser.parse_known_args(args=argv)

    # Set up logging verbosity before running the command, so
    # e.g. verbose messages related to argument handling errors work
    # properly. This works even for extension commands that haven't
    # been instantiated yet, because --verbose is an option to the top
    # level parser, and the command run() method doesn't get called
    # until later.
    log.set_verbosity(args.verbose)

    log.dbg('args namespace:', args, level=log.VERBOSE_EXTREME)

    # Try to set ZEPHYR_BASE. It would be nice to get rid of this
    # someday and just have extensions that need it set this variable.
    if args.command and args.command not in ['init', 'help'] and not args.help:
        set_zephyr_base(args)

    # If we were run as 'west -h ...' or 'west --help ...',
    # monkeypatch the args namespace so we end up running Help.  The
    # user might have also provided a command. If so, print help about
    # that command.
    if args.help or args.command is None:
        args.command_name = args.command
        args.command = 'help'

    # Finally, run the command.
    try:
        if args.command in extensions_by_name:
            # Check a program invariant. We should never get here
            # unless we were able to parse the manifest. That's where
            # information about extensions is gained.
            assert mve is None, \
                'internal error: running extension "{}" ' \
                'but got ManifestVersionError'.format(args.command)

            # This does not return. get_extension_commands() ensures
            # that extensions do not shadow built-in command names, so
            # checking this first is safe.
            run_extension(extensions_by_name[args.command], topdir, argv,
                          manifest)
        else:
            if mve:
                if args.command == 'help':
                    log.wrn(
                        _mve_msg(mve, suggest_ugprade=False) +
                        '\n  Cannot get extension command help, ' +
                        "and most commands won't run." +
                        '\n  To silence this warning, upgrade west.')
                elif args.command in ['config', 'topdir']:
                    # config and topdir are safe to run, but let's
                    # warn the user that most other commands won't be.
                    log.wrn(
                        _mve_msg(mve, suggest_ugprade=False) +
                        "\n  This should work, but most commands won't." +
                        '\n  To silence this warning, upgrade west.')
                elif args.command != 'init':
                    log.die(_mve_msg(mve))

            cmd = BUILTIN_COMMANDS.get(args.command, BUILTIN_COMMANDS['help'])
            cmd.run(args, unknown, topdir, manifest=manifest)
    except KeyboardInterrupt:
        sys.exit(0)
    except BrokenPipeError:
        sys.exit(0)
    except CalledProcessError as cpe:
        log.err('command exited with status {}: {}'.format(
            cpe.returncode, quote_sh_list(cpe.cmd)))
        if args.verbose:
            traceback.print_exc()
        sys.exit(cpe.returncode)
    except ExtensionCommandError as ece:
        msg = 'extension command "{}" could not be run{}.'.format(
            args.command, ': ' + ece.hint if ece.hint else '')
        if args.verbose:
            log.err(msg)
            traceback.print_exc()
        else:
            log.err(msg, 'See {} for a traceback.'.format(dump_traceback()))
        sys.exit(ece.returncode)
    except CommandContextError as cce:
        log.err('command', args.command, 'cannot be run in this context:',
                *cce.args)
        log.err('see {} for a traceback.'.format(dump_traceback()))
        sys.exit(cce.returncode)
    except CommandError as ce:
        # No need to dump_traceback() here. The command is responsible
        # for logging its own errors.
        sys.exit(ce.returncode)
    except (MalformedManifest, MalformedConfig) as malformed:
        log.die('\n  '.join(["can't load west manifest"] +
                            list(malformed.args)))