From da1fb89278daedbecd60414777647577b997f0d0 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 7 Jun 2018 21:46:50 -0400 Subject: [PATCH 001/226] doc: add initial west documentation This covers its design and scope, and provides usage and some implementation documentation on the existing flashing and debugging commands. Signed-off-by: Marti Bolivar --- doc/west/flash-debug.rst | 254 +++++++++++++++++++++++++++++++++++++++ doc/west/index.rst | 92 ++++++++++++++ 2 files changed, 346 insertions(+) create mode 100644 doc/west/flash-debug.rst create mode 100644 doc/west/index.rst diff --git a/doc/west/flash-debug.rst b/doc/west/flash-debug.rst new file mode 100644 index 00000000..ffdf3e7f --- /dev/null +++ b/doc/west/flash-debug.rst @@ -0,0 +1,254 @@ +.. _west-flash-debug: + +West: Flashing and Debugging +############################ + +West provides three commands for running and interacting with Zephyr +programs running on a board: ``flash``, ``debug``, and +``debugserver``. + +These use information stored in the CMake cache [#cmakecache]_ to +flash or attach a debugger to a board supported by Zephyr. The CMake +build system commands with the same names directly delegate to West. + +.. _west-flashing: + +Flashing: ``west flash`` +************************ + +.. tip:: Run ``west flash -h`` for additional help. + +Basics +====== + +From a Zephyr build directory, re-build the binary and flash it to +your board:: + + west flash + +Without options, the behavior is the same as ``ninja flash`` (or +``make flash``, etc.). + +To specify the build directory, use ``--build-dir`` (or ``-d``):: + + west flash --build-dir path/to/build/directory + +Choosing a Runner +================= + +If your board's Zephyr integration supports flashing with multiple +programs, you can specify which one to use using the ``--runner`` (or +``-r``) option. For example, if West flashes your board with +``nrfjprog`` by default, but it also supports JLink, you can override +the default with:: + + west flash --runner jlink + +See :ref:`west-runner` below for more information on the ``runner`` +library used by West. The list of runners which support flashing can +be obtained with ``west flash -H``; if run from a build directory or +with ``--build-dir``, this will print additional information on +available runners for your board. + +Configuration Overrides +======================= + +The CMake cache contains default values West uses while flashing, such +as where the board directory is on the file system, the path to the +kernel binaries to flash in several formats, and more. You can +override any of this configuration at runtime with additional options. + +For example, to override the HEX file containing the Zephyr image to +flash (assuming your runner expects a HEX file), but keep other +flash configuration at default values:: + + west flash --kernel-hex path/to/some/other.hex + +The ``west flash -h`` output includes a complete list of overrides +supported by all runners. + +Runner-Specific Overrides +========================= + +Each runner may support additional options related to flashing. For +example, some runners support an ``--erase`` flag, which mass-erases +the flash storage on your board before flashing the Zephyr image. + +To view all of the available options for the runners your board +supports, as well as their usage information, use ``--context`` (or +``-H``):: + + west flash --context + +.. important:: + + Note the capital H in the short option name. This re-runs the build + in order to ensure the information displayed is up to date! + +When running West outside of a build directory, ``west flash -H`` just +prints a list of runners. You can use ``west flash -H -r +`` to print usage information for options supported by +that runner. + +For example, to print usage information about the ``jlink`` runner:: + + west flash -H -r jlink + +.. _west-debugging: + +Debugging: ``west debug``, ``west debugserver`` +*********************************************** + +.. tip:: + + Run ``west debug -h`` or ``west debugserver -h`` for additional help. + +Basics +====== + +From a Zephyr build directory, to attach a debugger to your board and +open up a debug console (e.g. a GDB session):: + + west debug + +To attach a debugger to your board and open up a local network port +you can connect a debugger to (e.g. an IDE debugger):: + + west debugserver + +Without options, the behavior is the same as ``ninja debug`` and +``ninja debugserver`` (or ``make debug``, etc.). + +To specify the build directory, use ``--build-dir`` (or ``-d``):: + + west debug --build-dir path/to/build/directory + west debugserver --build-dir path/to/build/directory + +Choosing a Runner +================= + +If your board's Zephyr integration supports debugging with multiple +programs, you can specify which one to use using the ``--runner`` (or +``-r``) option. For example, if West debugs your board with +``pyocd-gdbserver`` by default, but it also supports JLink, you can +override the default with:: + + west debug --runner jlink + west debugserver --runner jlink + +See :ref:`west-runner` below for more information on the ``runner`` +library used by West. The list of runners which support debugging can +be obtained with ``west debug -H``; if run from a build directory or +with ``--build-dir``, this will print additional information on +available runners for your board. + +Configuration Overrides +======================= + +The CMake cache contains default values West uses for debugging, such +as where the board directory is on the file system, the path to the +kernel binaries containing symbol tables, and more. You can override +any of this configuration at runtime with additional options. + +For example, to override the ELF file containing the Zephyr binary and +symbol tables (assuming your runner expects an ELF file), but keep +other debug configuration at default values:: + + west debug --kernel-elf path/to/some/other.elf + west debugserver --kernel-elf path/to/some/other.elf + +The ``west debug -h`` output includes a complete list of overrides +supported by all runners. + +Runner-Specific Overrides +========================= + +Each runner may support additional options related to debugging. For +example, some runners support flags which allow you to set the network +ports used by debug servers. + +To view all of the available options for the runners your board +supports, as well as their usage information, use ``--context`` (or +``-H``):: + + west debug --context + +(The command ``west debugserver --context`` will print the same output.) + +.. important:: + + Note the capital H in the short option name. This re-runs the build + in order to ensure the information displayed is up to date! + +When running West outside of a build directory, ``west debug -H`` just +prints a list of runners. You can use ``west debug -H -r +`` to print usage information for options supported by +that runner. + +For example, to print usage information about the ``jlink`` runner:: + + west debug -H -r jlink + +.. _west-runner: + +Library Backend: ``west.runner`` +******************************** + +In keeping with West's :ref:`west-design-constraints`, the flash and +debug commands are wrappers around a separate library that is part of +West, and can be used by other code. + +This library is the ``west.runner`` subpackage of West itself. The +central abstraction within this library is ``ZephyrBinaryRunner``, an +abstract class which represents *runner* objects, which can flash +and/or debug Zephyr programs. The set of available runners is +determined by the imported subclasses of ``ZephyrBinaryRunner``. +``ZephyrBinaryRunner`` is available in the ``west.runner.core`` +module; individual runner implementations are in other submodules, +such as ``west.runner.nrfjprog``, ``west.runner.openocd``, etc. + +Developers can add support for new ways to flash and debug Zephyr +programs by implementing additional runners. To get this support into +upstream Zephyr, the runner should be added into a new or existing +``west.runner`` module, and imported from +:file:`west/runner/__init__.py`. + +.. important:: + + Submit any changes to West to its own separate Git repository + (https://github.com/zephyrproject-rtos/west), not to the copy of + West currently present in the Zephyr tree. This copy is a temporary + measure; when West learns how to manage multiple repositories, the + copy will be removed. + +API documentation for the core module follows. + +.. automodule:: west.runner.core + :members: + +Doing it By Hand +**************** + +If you prefer not to use West to flash or debug your board, simply +inspect the build directory for the binaries output by the build +system. These will be named something like ``zephyr/zephyr.elf``, +``zephyr/zephyr.hex``, etc., depending on your board's build system +integration. These binaries may be flashed to a board using +alternative tools of your choice, or used for debugging as needed, +e.g. as a source of symbol tables. + +By default, these West commands rebuild binaries before flashing and +debugging. This can of course also be accomplished using the usual +targets provided by Zephyr's build system (in fact, that's how West +does it). + +.. rubric:: Footnotes + +.. [#cmakecache] + + The CMake cache is a file containing saved variables and values + which is created by CMake when it is first run to generate a build + system. See the `cmake(1)`_ manual for more details. + +.. _cmake(1): + https://cmake.org/cmake/help/latest/manual/cmake.1.html diff --git a/doc/west/index.rst b/doc/west/index.rst new file mode 100644 index 00000000..6dd12327 --- /dev/null +++ b/doc/west/index.rst @@ -0,0 +1,92 @@ +.. _west: + +West (Experimental) +################### + +The Zephyr project is developing a swiss-army knife command line tool +named ``west``. (Zephyr is an English name for the Greek god of the +west wind.) + +West is developed in its own `repository on GitHub`_. A copy is +currently maintained in Zephyr's :file:`scripts/meta/west` directory. + +Usage +***** + +West's usage is similar to Git's: general options are followed by a +command, which may also take options and arguments:: + + $ west [common-opts] [command-opts] [] + +Usage guides for specific groups of subcommands are in the following +pages. + +.. toctree:: + + flash-debug.rst + +(This list will expand as additional features are developed.) + +Planned Features +**************** + +Additional features are under development for future versions of +Zephyr: + +- Building Zephyr images. + +- Running Zephyr in emulation. + +- Bootloader integration: bootloader-aware image building, signing, + and flashing, as well as building and flashing the bootloader itself. + +- Multiple repository support: fetching and updating repositories that + integrate with Zephyr, such as `MCUboot`_, `OpenThread`_ and others. + +See `Zephyr issue #6205`_ for more details and discussion. + +.. _west-design-constraints: + +Design Constraints +****************** + +West is: + +- **Optional**: it is always *possible* to drop back to "raw" + command-line tools, i.e. use Zephyr without using West. It may not + always be *convenient* to do so, however. (If all of West's features + were already conveniently available, there would be no reason to + develop it.) + +- **Compatible with CMake**: building, flashing and debugging, and + emulator support will always remain compatible with direct use of + CMake. + +- **Cross-platform**: West is written in Python 3, and works on all + platforms supported by Zephyr. + +- **Usable as a Library**: whenever possible, West features are + implemented as libraries that can be used standalone in other + programs, along with separate command line interfaces that wrap + them. West itself is a Python package named ``west``; its libraries + are implemented as subpackages. + +- **Conservative about features**: no features will be accepted without + strong and compelling motivation. + +- **Clearly specified**: West's behavior in cases where it wraps other + commands is clearly specified and documented. This enables + interoperability with third party tools, and means Zephyr developers + can always find out what is happening "under the hood" when using West. + +.. _repository on GitHub: + https://github.com/zephyrproject-rtos/west + +.. _MCUboot: + https://mcuboot.com/ + +.. _OpenThread: + https://openthread.io/ + +.. _Zephyr issue #6205: + https://github.com/zephyrproject-rtos/zephyr/issues/6205 From e0451825bd108fb3cc8c1aa390aa079ea577009c Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 23 Sep 2018 07:04:35 -0600 Subject: [PATCH 002/226] scripts: update west to latest upstream version. Update to the latest west. This includes a new 'attach' command. There are also multi-repo commands, but those won't get exposed to the user unless they install Zephyr using "west init" + "west fetch" (and not, say, "git clone"). Replace the launchers; they now detect whether zephyr is part of a multi-repo installation, and run the west code in its own repository if that is the case. This also requires an update to: - the flash/debug CMakeLists.txt, as the new west package is no longer executable as a module and must have its main script run by the interpreter instead. - the documentation, to reflect a rename and with a hack to fix the automodule directive in flash-debug.rst for now Signed-off-by: Marti Bolivar --- doc/west/flash-debug.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/west/flash-debug.rst b/doc/west/flash-debug.rst index ffdf3e7f..e45e7166 100644 --- a/doc/west/flash-debug.rst +++ b/doc/west/flash-debug.rst @@ -191,26 +191,26 @@ For example, to print usage information about the ``jlink`` runner:: .. _west-runner: -Library Backend: ``west.runner`` -******************************** +Library Backend: ``west.runners`` +********************************* In keeping with West's :ref:`west-design-constraints`, the flash and debug commands are wrappers around a separate library that is part of West, and can be used by other code. -This library is the ``west.runner`` subpackage of West itself. The +This library is the ``west.runners`` subpackage of West itself. The central abstraction within this library is ``ZephyrBinaryRunner``, an abstract class which represents *runner* objects, which can flash and/or debug Zephyr programs. The set of available runners is determined by the imported subclasses of ``ZephyrBinaryRunner``. -``ZephyrBinaryRunner`` is available in the ``west.runner.core`` +``ZephyrBinaryRunner`` is available in the ``west.runners.core`` module; individual runner implementations are in other submodules, -such as ``west.runner.nrfjprog``, ``west.runner.openocd``, etc. +such as ``west.runners.nrfjprog``, ``west.runners.openocd``, etc. Developers can add support for new ways to flash and debug Zephyr programs by implementing additional runners. To get this support into upstream Zephyr, the runner should be added into a new or existing -``west.runner`` module, and imported from +``west.runners`` module, and imported from :file:`west/runner/__init__.py`. .. important:: @@ -223,7 +223,7 @@ upstream Zephyr, the runner should be added into a new or existing API documentation for the core module follows. -.. automodule:: west.runner.core +.. automodule:: west.runners.core :members: Doing it By Hand From d3c4a8d2b07958d76fd705d5a61f73967557c954 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Thu, 1 Nov 2018 22:02:30 +0100 Subject: [PATCH 003/226] scripts: west: Add documentation for the multi-repo commands Explain multi-repo concepts like manifests and projects, give an overview of the currently implemented commands, and give an example of a potential workflow. There's no way to submit a multi-repo change for review yet, so this is still experimental. Signed-off-by: Ulf Magnusson --- doc/west/flash-debug.rst | 4 +- doc/west/index.rst | 1 + doc/west/repo-tool.rst | 302 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 doc/west/repo-tool.rst diff --git a/doc/west/flash-debug.rst b/doc/west/flash-debug.rst index e45e7166..9a709cc8 100644 --- a/doc/west/flash-debug.rst +++ b/doc/west/flash-debug.rst @@ -1,7 +1,7 @@ .. _west-flash-debug: -West: Flashing and Debugging -############################ +Flashing and Debugging +###################### West provides three commands for running and interacting with Zephyr programs running on a board: ``flash``, ``debug``, and diff --git a/doc/west/index.rst b/doc/west/index.rst index 6dd12327..7281baf0 100644 --- a/doc/west/index.rst +++ b/doc/west/index.rst @@ -24,6 +24,7 @@ pages. .. toctree:: flash-debug.rst + repo-tool.rst (This list will expand as additional features are developed.) diff --git a/doc/west/repo-tool.rst b/doc/west/repo-tool.rst new file mode 100644 index 00000000..7c6d33d5 --- /dev/null +++ b/doc/west/repo-tool.rst @@ -0,0 +1,302 @@ +.. _west-multi-repo: + +Multi-repository management +########################### + +.. note:: + + Zephyr is currently not managed as a multi-repo. This page describes an + upcoming tool and potential workflow. + +West includes a set of commands for working with projects composed of multiple +Git repositories (a *multi-repo*), similar to Google's `repo +`_ tool. + +The rest of this page introduces multi-repo concepts and gives an overview of +the multi-repo commands, along with an example workflow. + +.. note:: + + The multi-repo commands are meant to augment Git in minor ways for + multi-repo work, not replace it. For tasks that aren't multi-repo-related, + use plain Git commands. + + This page explains what the West multi-repo commands do behind the scenes. + +Manifests +========= + +A *manifest* is a `YAML `_ file that gives the URL and +revision for each repository in the multi-repo (each *project*), possibly along +with other information. Manifests are normally stored in a separate Git +repository. + +Running ``west init`` to initialize a West installation will clone the selected +manifest repository. Running ``west init`` without specifying a manifest +repository will use `a default manifest repository +`_ for Zephyr. A different +manifest repository can be selected with ``west init -m URL``. + +The format of the West manifest is described by a `pykwalify +`_ schema, found `here +`_. + +The ``manifest-rev`` branch +*************************** + +West creates a branch named ``manifest-rev`` in each project, pointing to the +project's manifest revision (or, more specifically, to the commit the revision +resolves to). The ``manifest-rev`` branch is updated whenever project data is +fetched (the `command overview`_ below explains which commands fetch project +data). + +All work branches created using West track the ``manifest-rev`` branch. Several +multi-repo commands also use ``manifest-rev`` as a reference for the upstream +revision (as of the most recent fetch). + +.. note:: + + ``manifest-rev`` is a normal Git branch, and is only treated specially by + name. If you delete or otherwise modify it, it will be recreated/reset when + upstream data is next fetched by ``west``, as if through ``git reset + --hard`` (though ``git update-ref`` is used internally). + + Since ``manifest-rev`` represents the upstream revision as of the most + recent fetch, it is normally a bad idea to modify it. + + ``manifest-rev`` was added to allow branches to track SHA revisions, and to + give a consistent reference for the upstream revision regardless of how the + manifest changes over time. + +Command overview +================ + +This section gives a quick overview of the multi-repo commands, split up by +functionality. All commands loosely mimic the corresponding Git command, but in +a multi-repo context (``west fetch`` fetches upstream data without updating +local work branches, etc.) + +Passing no projects to commands that accept a list of projects usually means to +run the command for all projects listed in the manifest. + +.. note:: + + For the most up-to-date documentation, see the command help texts (e.g. + ``west fetch --help``). Only the most important flags are mentioned here. + +Cloning and updating projects +***************************** + +After running ``west init`` to initialize West (e.g., with the default Zephyr +manifest), the following commands will clone/update projects. + +Except for ``west rebase``, all commands in this section implicitly update the +manifest repository, fetch upstream data, and update the ``manifest-rev`` +branch. + +.. note:: + + To implement self-updates, ``west init`` also clones a repository with the + West source code, which is updated whenever the manifest is. The ``west`` + command is implemented as a thin wrapper that calls through to the code in + the cloned repository. The wrapper itself only implements the ``west init`` + command. + + This is the same model used by Google's ``repo`` tool. + +- ``west clone [-b BRANCH_NAME] [PROJECT ...]``: Clones the specified + projects (default: all projects). + + An initial branch named after the project's manifest revision is created in + each cloned repository. The names of branch and tag revisions are used as-is. + For qualified refs like ``refs/heads/foo``, the last component (``foo``) is + used. For SHA revisions, the generic name ``work`` is used. + + A different branch name can be specified with ``-b``. + + Like all branches created using West, the initial branch tracks + ``manifest-rev``. + +- ``west fetch [PROJECT ...]``: Fetches new upstream changes in each of the + specified projects (default: all projects), cloning them first if necessary. + Local branches are not updated (except for the special ``manifest-rev`` + branch). + + If a repository is cloned using ``west fetch``, the initial state is a + detached HEAD at ``manifest-rev``. + + .. note:: + + ``west clone`` is an alias for ``west fetch`` + ``west branch `` + (see below). + +- ``west pull [PROJECT ...]``: Fetches new upstream changes in each of the + specified projects (default: all projects) and rebases them on top of + ``manifest-rev``. + + This corresponds to ``git pull --rebase``, with the tracked branch taken as + ``manifest-rev``. + +- ``west rebase [PROJECT ...]``: Rebases each of the specified projects + (default: all cloned projects) on top of ``manifest-rev``. + + .. note:: + + ``west pull`` is an alias for ``west fetch`` + ``west rebase``. + +Working with branches +********************* + +The following commands are used to create, check out, and list branches that +span multiple projects (in reality, Git branches with identical names in +multiple repositories). + +- ``west branch [BRANCH_NAME [PROJECT ...]]``: Creates a branch + ``BRANCH_NAME`` in each of the specified projects (default: all cloned + projects). + + Like all branches created using West, the newly created branches track + ``manifest-rev``. + + If no arguments are passed to ``west branch``, local branches from all + projects are listed, along with the projects they appear in. + +- ``west checkout [-b] BRANCH_NAME [PROJECT ...]]``: Checks out the branch + ``BRANCH_NAME`` in each of the specified projects (default: all cloned + projects). This command is a no-op for projects that do not have the + specified branch. + + With ``-b``, creates and checks out the branch if it does not exist in a + project (like ``git checkout -b``), instead of ignoring the project. + +Miscellaneous commands +********************** + +These commands perform miscellaneous functions. + +- ``west list``: Lists project information from the manifest (URL, revision, + path, etc.), along with other manifest-related information. + +- ``west diff [PROJECT ...] [ARGUMENT ...]``: Runs a multi-repo ``git diff`` + for the specified projects (default: all cloned projects). + + Extra arguments are passed as-is to ``git diff``. + +- ``west status [PROJECT ...] [ARGUMENT ...]``: Like ``west diff``, for + running ``git status``. + +- ``west forall -c COMMAND [PROJECT ...]``: Runs the shell command ``COMMAND`` + within the top-level repository directory of each of the specified projects + (default: all cloned projects). + + If ``COMMAND`` consists of more than one word, it must be quoted to prevent + it from being split up by the shell. + + Note that ``west forall`` can be used to run any command, not just Git + commands. To run a Git command, do ``west forall -c 'git ...'``. + +- ``west update [--update-manifest] [--update-west]``: Updates the manifest + and/or west repositories. With no arguments, both are updated. + + Normally, the manifest and west repositories are updated automatically + whenever a command that fetches upstream data is run (this behavior can be + suppressed for the duration of a single command by passing ``--no-update``). + If the manifest or west repository has local modifications and cannot be + fast-forwarded to the new version, the update of the repository is skipped + (with a warning). + +Example workflow +================ + +This section gives an example workflow that clones the Zephyr repositories, +creates and switches between two work branches, updates (rebases) a work branch +to the latest manifest revision, and inspects upstream changes. + +1. First, we initialize West with the default Zephyr manifest, and clone all + projects: + + .. code-block:: console + + $ west init + $ west clone + + .. note:: + + Repositories can also be cloned with ``west fetch``. The only difference + between ``west fetch`` and ``west clone`` is that no initial work branch + is created by ``west fetch``. Instead, the initial state with ``west + fetch`` is a detached ``HEAD`` at ``manifest-rev``. + + The initial work branch created by ``west clone`` is named after the + project's manifest revision. We don't do any work on the initial work + branch in this example, and create our own work branches instead. + +2. Next, we create and check out a branch ``xy-feature`` for implementing a + feature that spans the ``proj-x`` and ``proj-y`` projects: + + .. code-block:: console + + $ west checkout -b xy-feature proj-x proj-y + + This creates a Git branch named ``xy-feature`` in ``proj-x`` and ``proj-y``. + The new branches are automatically set up to track the ``manifest-rev`` + branch in their respective repositories. + + We work on the repositories as usual. + +3. While working on the feature, an urgent bug comes up that spans all + projects. We use ordinary Git commands to commit/stash the partially + implemented feature, and then check out a new branch for fixing the bug: + + .. code-block:: console + + $ west checkout -b global-fix + +4. After fixing the bug, we want to switch back to working on the feature, but + we forgot its branch name. We list branches with ``west branch`` to remind + ourselves, and then switch back: + + .. code-block:: console + + $ west checkout xy-feature + + This command only affects the ``proj-x`` and ``proj-y`` repositories, since + only those have the ``xy-feature`` branch. + +5. We now update (rebase) the ``proj-x`` and ``proj-y`` repositories, to get + get any new upstream changes into the ``xy-feature`` branch: + + .. code-block:: console + + $ west pull proj-x proj-y + +6. After doing more work, we want to see if more changes have been added + upstream, but we don't want to rebase yet. Instead, we just fetch changes in + all projects: + + .. code-block:: console + + $ west fetch + + This command fetches the upstream revision specified in the manifest and + updates the ``manifest-rev`` branch to point to it, for all projects. Local + work branches are not touched. + +7. Running ``west status`` or ``git status`` now shows that ``manifest-rev`` + is ahead of the ``xy-feature`` branch in ``proj-x``, meaning there are new + upstream changes. + + We want to update ``proj-x``. This could be done with ``west pull proj-x``, + but since the ``xy-feature`` branch tracks the ``manifest-rev`` branch, we + decide to mix it up a bit with a plain Git command inside the ``proj-x`` + repository: + + .. code-block:: console + + $ git pull --rebase + + .. note:: + + In general, do not assume that multi-repo commands are "better" where a + plain Git command will do. In particular, the multi-repo commands are not + meant to replicate every feature of the corresponding Git commands. From 15d004892bdbe920149235606c2df142ac287c88 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 5 Jan 2019 10:23:34 -0500 Subject: [PATCH 004/226] doc: restructure documentation With the new theme we are able to have more section in the top level. Move things around and expose the most important sections in the top table of content. Signed-off-by: Anas Nashif --- doc/{ => tools}/west/flash-debug.rst | 0 doc/{ => tools}/west/index.rst | 0 doc/{ => tools}/west/repo-tool.rst | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename doc/{ => tools}/west/flash-debug.rst (100%) rename doc/{ => tools}/west/index.rst (100%) rename doc/{ => tools}/west/repo-tool.rst (100%) diff --git a/doc/west/flash-debug.rst b/doc/tools/west/flash-debug.rst similarity index 100% rename from doc/west/flash-debug.rst rename to doc/tools/west/flash-debug.rst diff --git a/doc/west/index.rst b/doc/tools/west/index.rst similarity index 100% rename from doc/west/index.rst rename to doc/tools/west/index.rst diff --git a/doc/west/repo-tool.rst b/doc/tools/west/repo-tool.rst similarity index 100% rename from doc/west/repo-tool.rst rename to doc/tools/west/repo-tool.rst From 2bc84133a79e8296c98b0de4f34dc8a6bfa790ee Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 12 Nov 2018 16:14:51 +0100 Subject: [PATCH 005/226] doc: scripts: Retrieve west path at runtime Since west is no longer part of the Zephyr tree, we can no longer hardcode its path anymore. Instead, use west itself to retrieve its path, in order to point the documentation build to the correct active west installation. This is optional, and the documentation build will still work if west is not installed on the system. Signed-off-by: Carles Cufi --- doc/tools/west/flash-debug.rst | 5 +---- doc/west/west-apis.rst | 10 ++++++++++ doc/west/west-not-found.rst | 10 ++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 doc/west/west-apis.rst create mode 100644 doc/west/west-not-found.rst diff --git a/doc/tools/west/flash-debug.rst b/doc/tools/west/flash-debug.rst index 9a709cc8..501a3475 100644 --- a/doc/tools/west/flash-debug.rst +++ b/doc/tools/west/flash-debug.rst @@ -221,10 +221,7 @@ upstream Zephyr, the runner should be added into a new or existing measure; when West learns how to manage multiple repositories, the copy will be removed. -API documentation for the core module follows. - -.. automodule:: west.runners.core - :members: +API documentation for the core module can be found in :ref:`west-apis`. Doing it By Hand **************** diff --git a/doc/west/west-apis.rst b/doc/west/west-apis.rst new file mode 100644 index 00000000..7eebad3d --- /dev/null +++ b/doc/west/west-apis.rst @@ -0,0 +1,10 @@ +:orphan: + +.. _west-apis: + +West APIs +######### + +.. automodule:: west.runners.core + :members: + diff --git a/doc/west/west-not-found.rst b/doc/west/west-not-found.rst new file mode 100644 index 00000000..e9ab2fbf --- /dev/null +++ b/doc/west/west-not-found.rst @@ -0,0 +1,10 @@ +:orphan: + +.. _west-apis: + +West APIs +######### + +The west APIs are not documented since west was missing during the +documentation build. + From bd63ec8ddad07537917bf5aea8ed94b831b6bb5d Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 12 Nov 2018 16:56:09 +0100 Subject: [PATCH 006/226] doc: Use west instead of Git to clone Zephyr Since west is no longer included in the Zephyr repository, instruct users to install and use west in order to obtain the Zephyr source code. Signed-off-by: Carles Cufi Signed-off-by: Torsten Rasmussen --- doc/tools/west/index.rst | 201 +++++++++++++++++++++++++++++++---- doc/tools/west/repo-tool.rst | 17 +-- 2 files changed, 192 insertions(+), 26 deletions(-) diff --git a/doc/tools/west/index.rst b/doc/tools/west/index.rst index 7281baf0..ba8f700b 100644 --- a/doc/tools/west/index.rst +++ b/doc/tools/west/index.rst @@ -1,14 +1,125 @@ .. _west: -West (Experimental) -################### +West +#### -The Zephyr project is developing a swiss-army knife command line tool -named ``west``. (Zephyr is an English name for the Greek god of the -west wind.) +The Zephyr project includes a swiss-army knife command line tool +named ``west`` (Zephyr is an English name for the Latin +`Zephyrus `_, the ancient Greek god +of the west wind). -West is developed in its own `repository on GitHub`_. A copy is -currently maintained in Zephyr's :file:`scripts/meta/west` directory. +West is developed in its own `repository on GitHub`_. + +West is used to obtain the source code for the Zephyr project and can also be +used to build, debug, and flash applications. + +History and motivation +********************** + +West was added to the Zephyr project to fulfill two fundamental requirements: + +* The ability to work with multiple Git repositories +* The ability to provide a user-friendly command-line interface to the Zephyr + build system and debug mechanisms + +During the development of west, a set of :ref:`west-design-constraints` were +identified to avoid the common pitfalls of tools of this kind. + +Multiple Git Repositories +========================= + +Zephyr intends to provide all required building blocks needed to deploy complex +IoT applications. This in turn means that the Zephyr project is much more than +an RTOS kernel, and is instead a collection of components that work together. +In this context, there are a few reasons to work with multiple Git +repositories in a standardized manner within the project: + +* Clean separation of Zephyr original code and imported projects and libraries +* Avoidance of license incompatibilities between original and imported code +* Reduction in size and scope of the core Zephyr codebase, with additional + repositories containing optional components instead of being imported + directly into the tree +* Safety and security certifications +* Enforcement of modularization of the components +* Out-of-tree development based on subsets of the supported boards and SoCs + +Command-line interface +====================== + +Zephyr uses CMake as its build system management tool, as described in +:ref:`application`. +While CMake is a very powerful system and language, its two-stage nature +as a build system generator makes it non-trivial to present the user with +a consistent set of command-line switches and options that enable advanced +usage of the build tool ultimately responsible for building, flashing, and +debugging the application. +West was introduced to unify and streamline the developer's experience when +working with Zephyr. It is very important to note that west does not +replace the CMake-based build system, but directly uses it and augments it. + +.. _west-struct: + +Structure +********* + +West is downloaded and installed on a system in two stages: + +* Bootstrapper: Installed using ``pip``, implements ``west init`` +* Installation: Installed using ``west init``, implements all other commands + +Additional information about the two parts can be found below. + +Bootstrapper +============ + +The bootstrapper module is distributed using `PyPi`_ (i.e. :file:`pip`) and it's +placed in the user's ``PATH`` becoming the only entry point to west. +It implements a single command: ``west init``. This command needs to be run +first to use the rest of functionality included in ``west``. The command +``west init`` will do the following: + +* Clone west itself in a :file:`west/west` folder +* Clone the manifest in a :file:`west/manifest` folder (additional information + on the manifest can be found in the :ref:`west-multi-repo` section) + +Once ``west init`` has been run, the bootstrapper will delegate the handling of +any west commands other than ``init`` to the cloned west installation. + +This means that there is a single bootstrapper instance installed at any time +(unless you use virtual environments), which can then be used to initialize as +many installations as needed. + +.. _west-struct-installation: + +Installation +============ + +A west installation is the result of running ``west init`` in an existing +folder, or ``west init `` to create and initialize a folder. As +described on the previous section, an installation always includes a special +:file:`west/` folder that contains a clone of both west itself and the manifest. +Additionally, and once ``west clone`` has been run, the installation will also +contain a clone of any repositories listed in the manifest. The directory tree +layout of an installation using the default Zephyr manifest therefore looks +like this: + +.. code-block:: console + + └── zephyrproject + ├── west + │   ├── config + │   ├── manifest + │   └── west + └── zephyr + +Additionally, ``west init`` creates a configuration file :file:`west/config` +that stores configuration metadata about the west installation. + +To learn more about west's handling of multiple repositories refer to +:ref:`west-multi-repo`. + +The west bootstrapper delegates handling for all commands except ``init`` to +the installation in :file:`west/west`. Usage ***** @@ -16,15 +127,16 @@ Usage West's usage is similar to Git's: general options are followed by a command, which may also take options and arguments:: - $ west [common-opts] [command-opts] [] + west [common-opts] [command-opts] [] Usage guides for specific groups of subcommands are in the following pages. .. toctree:: + :maxdepth: 1 - flash-debug.rst repo-tool.rst + flash-debug.rst (This list will expand as additional features are developed.) @@ -34,17 +146,14 @@ Planned Features Additional features are under development for future versions of Zephyr: -- Building Zephyr images. - - Running Zephyr in emulation. - Bootloader integration: bootloader-aware image building, signing, and flashing, as well as building and flashing the bootloader itself. -- Multiple repository support: fetching and updating repositories that - integrate with Zephyr, such as `MCUboot`_, `OpenThread`_ and others. +- Additional multiple repository support: fetching and updating repositories + that integrate with Zephyr, such as `MCUboot`_, `OpenThread`_ and others. -See `Zephyr issue #6205`_ for more details and discussion. .. _west-design-constraints: @@ -54,8 +163,9 @@ Design Constraints West is: - **Optional**: it is always *possible* to drop back to "raw" - command-line tools, i.e. use Zephyr without using West. It may not - always be *convenient* to do so, however. (If all of West's features + command-line tools, i.e. use Zephyr without using west (although west itself + might need to be installed and accessible to the build system). It may not + always be *convenient* to do so, however. (If all of west's features were already conveniently available, there would be no reason to develop it.) @@ -66,7 +176,7 @@ West is: - **Cross-platform**: West is written in Python 3, and works on all platforms supported by Zephyr. -- **Usable as a Library**: whenever possible, West features are +- **Usable as a Library**: whenever possible, west features are implemented as libraries that can be used standalone in other programs, along with separate command line interfaces that wrap them. West itself is a Python package named ``west``; its libraries @@ -78,11 +188,60 @@ West is: - **Clearly specified**: West's behavior in cases where it wraps other commands is clearly specified and documented. This enables interoperability with third party tools, and means Zephyr developers - can always find out what is happening "under the hood" when using West. + can always find out what is happening "under the hood" when using west. + +See `Zephyr issue #6205`_ and `Zephyr issue #6770`_ for more details and +discussion. + +.. _no-west: + +Using Zephyr without west +************************* + +There are many valid usecases to avoid using a meta-tool such as west which has +been custom-designed for a particular project and its requirements. +This section applies to Zephyr users who fall into one or more of these +categories: + +- Already use a multi-repository management system (for example Google repo) + +- Do not need additional functionality beyond compiling and linking + +In order to obtain the Zephyr source code and build it without the help of +west you will need to manually clone the repositories listed in the +`manifest file`_ one by one, at the path indicated in it. + +.. code-block:: console + + mkdir zephyrproject + cd zephyrproject + git clone https://github.com/zephyrproject-rtos/zephyr + # clone additional repositories listed in the manifest file + +If you want to manage Zephyr's repositories without west but still need to +use west's additional functionality (flashing, debugging, etc.) it is possible +to do so by manually creating an installation: + +.. code-block:: console + + # cd into zephyrproject if not already there + git clone https://github.com/zephyrproject-rtos/west.git + echo > west/.west_topdir + +After that, and in order for ``ninja`` to be able to invoke ``west`` you must +specify the west directory. This can be done as: + +- Set the environment variable ``WEST_DIR`` to point to the directory where + ``west`` was cloned +- Specify ``WEST_DIR`` when running ``cmake``, e.g. + ``cmake -DWEST_DIR= ...`` .. _repository on GitHub: https://github.com/zephyrproject-rtos/west +.. _PyPi: + https://pypi.org/project/west/ + .. _MCUboot: https://mcuboot.com/ @@ -91,3 +250,9 @@ West is: .. _Zephyr issue #6205: https://github.com/zephyrproject-rtos/zephyr/issues/6205 + +.. _Zephyr issue #6770: + https://github.com/zephyrproject-rtos/zephyr/issues/6770 + +.. _manifest file: + https://github.com/zephyrproject-rtos/manifest/blob/master/default.yml diff --git a/doc/tools/west/repo-tool.rst b/doc/tools/west/repo-tool.rst index 7c6d33d5..9770c0c3 100644 --- a/doc/tools/west/repo-tool.rst +++ b/doc/tools/west/repo-tool.rst @@ -217,8 +217,9 @@ to the latest manifest revision, and inspects upstream changes. .. code-block:: console - $ west init - $ west clone + west init zephyrproject + cd zephyrproject + west clone .. note:: @@ -236,7 +237,7 @@ to the latest manifest revision, and inspects upstream changes. .. code-block:: console - $ west checkout -b xy-feature proj-x proj-y + west checkout -b xy-feature proj-x proj-y This creates a Git branch named ``xy-feature`` in ``proj-x`` and ``proj-y``. The new branches are automatically set up to track the ``manifest-rev`` @@ -250,7 +251,7 @@ to the latest manifest revision, and inspects upstream changes. .. code-block:: console - $ west checkout -b global-fix + west checkout -b global-fix 4. After fixing the bug, we want to switch back to working on the feature, but we forgot its branch name. We list branches with ``west branch`` to remind @@ -258,7 +259,7 @@ to the latest manifest revision, and inspects upstream changes. .. code-block:: console - $ west checkout xy-feature + west checkout xy-feature This command only affects the ``proj-x`` and ``proj-y`` repositories, since only those have the ``xy-feature`` branch. @@ -268,7 +269,7 @@ to the latest manifest revision, and inspects upstream changes. .. code-block:: console - $ west pull proj-x proj-y + west pull proj-x proj-y 6. After doing more work, we want to see if more changes have been added upstream, but we don't want to rebase yet. Instead, we just fetch changes in @@ -276,7 +277,7 @@ to the latest manifest revision, and inspects upstream changes. .. code-block:: console - $ west fetch + west fetch This command fetches the upstream revision specified in the manifest and updates the ``manifest-rev`` branch to point to it, for all projects. Local @@ -293,7 +294,7 @@ to the latest manifest revision, and inspects upstream changes. .. code-block:: console - $ git pull --rebase + git pull --rebase .. note:: From fb205452faead1ba266f7cf52cce24063fe4b282 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Wed, 23 Jan 2019 13:18:16 +0100 Subject: [PATCH 007/226] doc: west: Move files to the correct location West documentation files now belong in doc/tools/west and not doc/west. Signed-off-by: Carles Cufi --- doc/{ => tools}/west/west-apis.rst | 0 doc/{ => tools}/west/west-not-found.rst | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename doc/{ => tools}/west/west-apis.rst (100%) rename doc/{ => tools}/west/west-not-found.rst (100%) diff --git a/doc/west/west-apis.rst b/doc/tools/west/west-apis.rst similarity index 100% rename from doc/west/west-apis.rst rename to doc/tools/west/west-apis.rst diff --git a/doc/west/west-not-found.rst b/doc/tools/west/west-not-found.rst similarity index 100% rename from doc/west/west-not-found.rst rename to doc/tools/west/west-not-found.rst From 922d4c1cdf868ef29b6690749f7ab6d89bcbf5f2 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Wed, 23 Jan 2019 14:56:00 +0100 Subject: [PATCH 008/226] doc: west: Overhaul documentation to match current model Overhaul the west documentation so that it matches the model that is currently implemented in the west repository. This model is no longer subject to change in the short or mid term, since it has been selected as the only viable one for multi-repo management using west. Signed-off-by: Carles Cufi --- doc/tools/west/index.rst | 62 +++-- doc/tools/west/repo-tool.rst | 419 +++++++++++++++++-------------- doc/tools/west/west-mr-model.png | Bin 0 -> 49639 bytes 3 files changed, 268 insertions(+), 213 deletions(-) create mode 100755 doc/tools/west/west-mr-model.png diff --git a/doc/tools/west/index.rst b/doc/tools/west/index.rst index ba8f700b..c7b80e79 100644 --- a/doc/tools/west/index.rst +++ b/doc/tools/west/index.rst @@ -13,6 +13,8 @@ West is developed in its own `repository on GitHub`_. West is used to obtain the source code for the Zephyr project and can also be used to build, debug, and flash applications. +.. _west-history: + History and motivation ********************** @@ -43,6 +45,9 @@ repositories in a standardized manner within the project: * Enforcement of modularization of the components * Out-of-tree development based on subsets of the supported boards and SoCs +See :ref:`west-multi-repo` for a detailed explanation of west's handling of +multiple repository management. + Command-line interface ====================== @@ -57,17 +62,38 @@ West was introduced to unify and streamline the developer's experience when working with Zephyr. It is very important to note that west does not replace the CMake-based build system, but directly uses it and augments it. +See :ref:`west-flash-debug` for a detailed explanation of the flash and debug +command-line interface exposed by west. + .. _west-struct: Structure ********* +West structure +============== + West is downloaded and installed on a system in two stages: * Bootstrapper: Installed using ``pip``, implements ``west init`` * Installation: Installed using ``west init``, implements all other commands -Additional information about the two parts can be found below. +Additional information about the two distinct parts of west can be found in +the corresponding sections below. + +Repository structure +==================== + +Beyond west itself, the actual code repositories that west works with +are the following: + +* Manifest repository: Cloned by ``west init``, and managed afterward with Git + by the user. Contains the list of projects in the manifest :file:`west.yml` + file. In the case of upstream Zephyr, the zephyr repository is the manifest + repository. +* Projects: Cloned and managed by ``west update``. Listed in the manifest file. + +See :ref:`west-mr-model` for more information on the multi-repository layout. Bootstrapper ============ @@ -78,8 +104,9 @@ It implements a single command: ``west init``. This command needs to be run first to use the rest of functionality included in ``west``. The command ``west init`` will do the following: -* Clone west itself in a :file:`west/west` folder -* Clone the manifest in a :file:`west/manifest` folder (additional information +* Clone west itself in a :file:`.west/west` folder +* Clone the manifest repository in the folder specified by the manifest file's + (:file:`west.yml`) ``self.path`` section. Additional information on the manifest can be found in the :ref:`west-multi-repo` section) Once ``west init`` has been run, the bootstrapper will delegate the handling of @@ -97,29 +124,30 @@ Installation A west installation is the result of running ``west init`` in an existing folder, or ``west init `` to create and initialize a folder. As described on the previous section, an installation always includes a special -:file:`west/` folder that contains a clone of both west itself and the manifest. -Additionally, and once ``west clone`` has been run, the installation will also +:file:`.west/` folder that contains a clone of west itself, as well as a local +clone of the manifest repository (``zephyr`` in the default upstream case). +Additionally, and once ``west update`` has been run, the installation will also contain a clone of any repositories listed in the manifest. The directory tree layout of an installation using the default Zephyr manifest therefore looks like this: .. code-block:: console - └── zephyrproject - ├── west + └── zephyrproject/ + ├── .west/ │   ├── config - │   ├── manifest - │   └── west - └── zephyr + │   └── west/ + └── zephyr/ +    └── west.yml -Additionally, ``west init`` creates a configuration file :file:`west/config` +``west init`` also creates a configuration file :file:`.west/config` that stores configuration metadata about the west installation. To learn more about west's handling of multiple repositories refer to :ref:`west-multi-repo`. The west bootstrapper delegates handling for all commands except ``init`` to -the installation in :file:`west/west`. +the installation in :file:`.west/west`. Usage ***** @@ -190,7 +218,7 @@ West is: interoperability with third party tools, and means Zephyr developers can always find out what is happening "under the hood" when using west. -See `Zephyr issue #6205`_ and `Zephyr issue #6770`_ for more details and +See `Zephyr issue #6205`_ and for more details and discussion. .. _no-west: @@ -226,7 +254,8 @@ to do so by manually creating an installation: # cd into zephyrproject if not already there git clone https://github.com/zephyrproject-rtos/west.git - echo > west/.west_topdir + echo [manifest] > .west/config + echo path = zephyr >> .west/config After that, and in order for ``ninja`` to be able to invoke ``west`` you must specify the west directory. This can be done as: @@ -251,8 +280,5 @@ specify the west directory. This can be done as: .. _Zephyr issue #6205: https://github.com/zephyrproject-rtos/zephyr/issues/6205 -.. _Zephyr issue #6770: - https://github.com/zephyrproject-rtos/zephyr/issues/6770 - .. _manifest file: - https://github.com/zephyrproject-rtos/manifest/blob/master/default.yml + https://github.com/zephyrproject-rtos/zephyr/blob/master/west.yml diff --git a/doc/tools/west/repo-tool.rst b/doc/tools/west/repo-tool.rst index 9770c0c3..7054698e 100644 --- a/doc/tools/west/repo-tool.rst +++ b/doc/tools/west/repo-tool.rst @@ -1,19 +1,19 @@ .. _west-multi-repo: -Multi-repository management -########################### +West and Multi-repository +######################### -.. note:: - - Zephyr is currently not managed as a multi-repo. This page describes an - upcoming tool and potential workflow. +Introduction +************ West includes a set of commands for working with projects composed of multiple -Git repositories (a *multi-repo*), similar to Google's `repo +Git repositories (a *multi-repo*), similar to `Git Submodules +` and Google's `repo `_ tool. The rest of this page introduces multi-repo concepts and gives an overview of -the multi-repo commands, along with an example workflow. +the multi-repo commands, along with an example workflow. See +`Zephyr issue #6770`_ for additional background and discussion. .. note:: @@ -21,26 +21,185 @@ the multi-repo commands, along with an example workflow. multi-repo work, not replace it. For tasks that aren't multi-repo-related, use plain Git commands. - This page explains what the West multi-repo commands do behind the scenes. + This page explains what the west multi-repo commands do behind the scenes. + +Requirements +************ + +Although the motivation behind splitting the Zephyr codebase into multiple +repositories is outside of the scope of this page, the fundamental requirements +along with a clear justification of the choice not to use existing tools and +instead develop a new one, do belong here. +At the most fundamental level, the requirements for a transition to multiple +repositories in the Zephyr Project are: + +* *R1*: Keep externally maintained code outside of the main repository +* *R2*: Provide a tool that both Zephyr users and distributors can make use of + to benefit from and extend the functionality above +* *R3*: Allow overriding or removing repositories without having to make changes + to the zephyr repository +* *R4*: Support both continuous tracking and commit-based (bisectable) project + updating + +Topologies supported +******************** + +The requirements above lead us to the three main source code organization +topologies that we intend to address with west: + +#. *T1* Star topology with zephyr as the manifest repository: + + - The zephyr repository acts as the central repository and includes a + complete list of projects in itself + - Default (upstream) configuration + - Analogy with existing mechanisms: Git submodules with zephyr as the + superproject + +#. *T2* Star topology with an application repository as the manifest repository + + - The application repository acts as the central repository and includes a + complete list of projects in itself + - Useful for downstream distributions focused in a single application + repository + - Analogy with existing mechanisms: Git submodules with the application as + the superproject, zephyr as a submodule + +#. *T3* Forest topology with a set of trees all at the same level + + - A dedicated manifest repository contains only a list of repositories + - Useful for downstream distributions that track the latest ``HEAD`` on all + repositories + - Analogy with existing mechanisms: Google repo-based distribution + +Rationale for a custom tool +*************************** + +During the different stages of design and development for west, using already +established and proven multi-repo technologies was considered multiple times. +After careful analysis, no existing tool or mechanism was found suitable for +Zephyr’s use case set and requirements. The following two tools were examined +in detail: + +* Google repo + + - The tool is Python 2 only + - Does not play well with Windows + - It is poorly documented and maintained + - It does not fully support a set of bisectable repositories without + additional intervention (*R4*) + +* Git submodules + + - Does not fully support *R1*, since the externally maintained repositories + would still need to be inside the main zephyr Git tree + - Does not support *R3*. Downstream copies would need to either delete or + replace submodule definitions + - Does not support continuous tracking of the latest ``HEAD`` in external + repositories (*R4*) + - Requires hardcoding of the paths/locations of the external repositories -Manifests -========= +Finally, please see :ref:`west-history` for the motivations behind using a +single tool for both multi-repository management as well as building, debugging +and flashing. -A *manifest* is a `YAML `_ file that gives the URL and -revision for each repository in the multi-repo (each *project*), possibly along -with other information. Manifests are normally stored in a separate Git -repository. +.. _west-mr-model: -Running ``west init`` to initialize a West installation will clone the selected -manifest repository. Running ``west init`` without specifying a manifest -repository will use `a default manifest repository -`_ for Zephyr. A different -manifest repository can be selected with ``west init -m URL``. +Model +***** -The format of the West manifest is described by a `pykwalify +Manifest +======== + +A *manifest* is a `YAML `_ file that, at a minimum, gives the +URL and revision for each project repository in the multi-repo (each *project*). +The manifest is stored in the *manifest repository* and is named :file:`west.yml`. + +The format of the west manifest is described by a `pykwalify `_ schema, found `here `_. +A west-based Zephyr installation has a special manifest repository. This +repository contains the west manifest file named :file:`west.yml`. The west +manifest contains: + +* A list of the projects (Git repositories) in the installation and + metadata about them (where to clone them from, what revision to check out, + etc.). Externally maintained projects (vendor HALs, crypto libraries, etc) + will be moved into their own repositories as part of the transition to + multi-repository, and will be managed using this list. + +* Metadata about the manifest repository, such as what path to clone it into in + the Zephyr installation. + +* Optionally, a description of how to clone west itself (this allows users to + fork west itself, should that be necessary). + +* Additionally both the projects and the metadata about the manifest repository + can optionally include information about additional west commands (extensions) + that are contained inside the Git repositories. + +Repositories +============ + +There are therefore three types of repositories that exist in a west-based Zephyr +installation: + +* West repository: This is cloned by ``west init`` and placed in + :file:`.west/west` + +* Manifest repository: This is the repository that contains the :file:`west.yml` + manifest file described above which lists all the projects. The manifest + repository can either contain only the manifest itself or also have actual + code in it. In the case of the upstream Zephyr Project, the manifest + repository is the `zephyr repository `_, + which contains all zephyr source code except for externally maintained + projects, which are listed in the :file:`west.yml` manifest file. + It is the user's responsibility to update this repository using Git. + +* Project repositories: In the context of west, projects are source code + repositories that are listed in the manifest file, :file:`west.yml` contained + inside the manifest repository. West manages projects, updating them according + to the revisions present in the manifest file. + +West's view of multirepo history looks like this example (though some parts of +the example are specific to upstream Zephyr’s use of west): + +.. figure:: west-mr-model.png + :align: center + :alt: West multi-repo history + :figclass: align-center + + West multi-repo history + +The history of the manifest repository is the line of Git commits which is +"floating" on top of a plane (parent commits point to child commits using +solid arrows.) The plane contains the Git commit history of the projects, with +each project's history boxed in by a rectangle. + +The commits in the manifest repository (again, for upstream Zephyr this is the +zephyr repository itself) each have a manifest file. The manifest file in each +zephyr commit gives the corresponding commits which it expects in the other +projects. These are shown using dotted line arrows in the diagram. + +Notice a few important details about the above picture: + +- Other projects can stay at the same versions between two zephyr commits + (like ``P2`` does between zephyr commits ``A → B``, and both ``P1`` and + ``P3`` do in ``F → G``). +- Other projects can move forward in history between two zephyr commits (``P3`` + from ``A → B``). +- A project can also move backwards in its history as zephyr moves forward + (like ``P3`` from zephyr commits ``C → D``). One use for this is to "revert" + a regression by moving the other project to a version before it was + introduced. +- Not all zephyr manifests have the same other projects (``P2`` is not a part + of the installation at zephyr commits ``F`` and ``G``). +- Two zephyr commits can have the same external commits (like ``F`` and ``G``). +- Not all commits in some projects are associated with a zephyr commit (``P3`` + "jumps" multiple commits in its history between zephyr commits ``B → C``). +- Every zephyr commit’s manifest refers to exactly one version in each of the + other projects it cares about. + The ``manifest-rev`` branch *************************** @@ -50,7 +209,7 @@ resolves to). The ``manifest-rev`` branch is updated whenever project data is fetched (the `command overview`_ below explains which commands fetch project data). -All work branches created using West track the ``manifest-rev`` branch. Several +All work branches created using west track the ``manifest-rev`` branch. Several multi-repo commands also use ``manifest-rev`` as a reference for the upstream revision (as of the most recent fetch). @@ -68,13 +227,16 @@ revision (as of the most recent fetch). give a consistent reference for the upstream revision regardless of how the manifest changes over time. +.. note:: + West does not create a ``manifest-rev`` branch in the manifest repository, + since west does not manage the manifest repository's branches or revisions. + Command overview ================ This section gives a quick overview of the multi-repo commands, split up by -functionality. All commands loosely mimic the corresponding Git command, but in -a multi-repo context (``west fetch`` fetches upstream data without updating -local work branches, etc.) +functionality. Some commands loosely mimic the corresponding Git command, but in +a multi-repo context (``west diff`` shows local changes on all repositories). Passing no projects to commands that accept a list of projects usually means to run the command for all projects listed in the manifest. @@ -82,92 +244,57 @@ run the command for all projects listed in the manifest. .. note:: For the most up-to-date documentation, see the command help texts (e.g. - ``west fetch --help``). Only the most important flags are mentioned here. + ``west diff --help``). Only the most important flags are mentioned here. Cloning and updating projects ***************************** -After running ``west init`` to initialize West (e.g., with the default Zephyr +After running ``west init`` to initialize west (e.g., with the default Zephyr manifest), the following commands will clone/update projects. -Except for ``west rebase``, all commands in this section implicitly update the -manifest repository, fetch upstream data, and update the ``manifest-rev`` -branch. - .. note:: To implement self-updates, ``west init`` also clones a repository with the - West source code, which is updated whenever the manifest is. The ``west`` + west source code, which is updated whenever the projects are. The ``west`` command is implemented as a thin wrapper that calls through to the code in the cloned repository. The wrapper itself only implements the ``west init`` command. This is the same model used by Google's ``repo`` tool. -- ``west clone [-b BRANCH_NAME] [PROJECT ...]``: Clones the specified +- ``west init [-l] [-m URL] [--mr REVISION] [PATH]``: Initializes a west + installation. + + This command can be invoked in two distinct ways. + If you already have a local copy or clone of the manifest repository, you can + use the ``-l`` switch to instruct west to initialize an installation around + the existing clone, without modifying it. For example, + ``west init -l path/to/zephyr`` is useful if you already have cloned the + zephyr repository in the past using Git and now want to initialize a west + installation around it. + If you however want to initialize an installation directly from the remote + repository, you have the option to specify its URL using the ``-m`` switch + and/or its revision with the ``--mr`` one. For example, invoking west with: + ``west init -m https://github.com/zephyrproject-rtos/zephyr --mr v1.15.0`` + would clone the upstream official zephyr repository at the tagged release + v1.15.0. + +- ``west update [PROJECT ...]``: Clones or updates the specified projects (default: all projects). + This command will parse the manifest file (:file:`west.yml`) in the manifest + repository, clone all project repositories that are not already present + locally and finally update all projects to the revision specified in the + manifest file. An initial branch named after the project's manifest revision is created in - each cloned repository. The names of branch and tag revisions are used as-is. - For qualified refs like ``refs/heads/foo``, the last component (``foo``) is - used. For SHA revisions, the generic name ``work`` is used. - - A different branch name can be specified with ``-b``. - - Like all branches created using West, the initial branch tracks - ``manifest-rev``. - -- ``west fetch [PROJECT ...]``: Fetches new upstream changes in each of the - specified projects (default: all projects), cloning them first if necessary. - Local branches are not updated (except for the special ``manifest-rev`` - branch). - - If a repository is cloned using ``west fetch``, the initial state is a - detached HEAD at ``manifest-rev``. - - .. note:: - - ``west clone`` is an alias for ``west fetch`` + ``west branch `` - (see below). - -- ``west pull [PROJECT ...]``: Fetches new upstream changes in each of the - specified projects (default: all projects) and rebases them on top of - ``manifest-rev``. - - This corresponds to ``git pull --rebase``, with the tracked branch taken as - ``manifest-rev``. - -- ``west rebase [PROJECT ...]``: Rebases each of the specified projects - (default: all cloned projects) on top of ``manifest-rev``. - - .. note:: - - ``west pull`` is an alias for ``west fetch`` + ``west rebase``. - -Working with branches -********************* - -The following commands are used to create, check out, and list branches that -span multiple projects (in reality, Git branches with identical names in -multiple repositories). + each cloned project repository. The names of branch and tag revisions are + used as-is. For qualified refs like ``refs/heads/foo``, the last component + (``foo``) is used. For SHA revisions, a detached ``HEAD`` is checked out. -- ``west branch [BRANCH_NAME [PROJECT ...]]``: Creates a branch - ``BRANCH_NAME`` in each of the specified projects (default: all cloned - projects). - - Like all branches created using West, the newly created branches track - ``manifest-rev``. - - If no arguments are passed to ``west branch``, local branches from all - projects are listed, along with the projects they appear in. - -- ``west checkout [-b] BRANCH_NAME [PROJECT ...]]``: Checks out the branch - ``BRANCH_NAME`` in each of the specified projects (default: all cloned - projects). This command is a no-op for projects that do not have the - specified branch. - - With ``-b``, creates and checks out the branch if it does not exist in a - project (like ``git checkout -b``), instead of ignoring the project. +.. note:: + West uses ``git checkout`` to switch each project to the revision specified + in the manifest repository. This is typically a safe operation that will not + modify any branches or staged work you might have. Miscellaneous commands ********************** @@ -195,109 +322,11 @@ These commands perform miscellaneous functions. Note that ``west forall`` can be used to run any command, not just Git commands. To run a Git command, do ``west forall -c 'git ...'``. -- ``west update [--update-manifest] [--update-west]``: Updates the manifest - and/or west repositories. With no arguments, both are updated. +- ``west selfupdate``: Updates the west repository. - Normally, the manifest and west repositories are updated automatically - whenever a command that fetches upstream data is run (this behavior can be + Normally, the west repository is updated automatically whenever a command + that fetches upstream data is run (this behavior can be suppressed for the duration of a single command by passing ``--no-update``). - If the manifest or west repository has local modifications and cannot be - fast-forwarded to the new version, the update of the repository is skipped - (with a warning). - -Example workflow -================ - -This section gives an example workflow that clones the Zephyr repositories, -creates and switches between two work branches, updates (rebases) a work branch -to the latest manifest revision, and inspects upstream changes. - -1. First, we initialize West with the default Zephyr manifest, and clone all - projects: - - .. code-block:: console - - west init zephyrproject - cd zephyrproject - west clone - - .. note:: - - Repositories can also be cloned with ``west fetch``. The only difference - between ``west fetch`` and ``west clone`` is that no initial work branch - is created by ``west fetch``. Instead, the initial state with ``west - fetch`` is a detached ``HEAD`` at ``manifest-rev``. - - The initial work branch created by ``west clone`` is named after the - project's manifest revision. We don't do any work on the initial work - branch in this example, and create our own work branches instead. - -2. Next, we create and check out a branch ``xy-feature`` for implementing a - feature that spans the ``proj-x`` and ``proj-y`` projects: - - .. code-block:: console - - west checkout -b xy-feature proj-x proj-y - - This creates a Git branch named ``xy-feature`` in ``proj-x`` and ``proj-y``. - The new branches are automatically set up to track the ``manifest-rev`` - branch in their respective repositories. - - We work on the repositories as usual. - -3. While working on the feature, an urgent bug comes up that spans all - projects. We use ordinary Git commands to commit/stash the partially - implemented feature, and then check out a new branch for fixing the bug: - - .. code-block:: console - - west checkout -b global-fix - -4. After fixing the bug, we want to switch back to working on the feature, but - we forgot its branch name. We list branches with ``west branch`` to remind - ourselves, and then switch back: - - .. code-block:: console - - west checkout xy-feature - - This command only affects the ``proj-x`` and ``proj-y`` repositories, since - only those have the ``xy-feature`` branch. - -5. We now update (rebase) the ``proj-x`` and ``proj-y`` repositories, to get - get any new upstream changes into the ``xy-feature`` branch: - - .. code-block:: console - - west pull proj-x proj-y - -6. After doing more work, we want to see if more changes have been added - upstream, but we don't want to rebase yet. Instead, we just fetch changes in - all projects: - - .. code-block:: console - - west fetch - - This command fetches the upstream revision specified in the manifest and - updates the ``manifest-rev`` branch to point to it, for all projects. Local - work branches are not touched. - -7. Running ``west status`` or ``git status`` now shows that ``manifest-rev`` - is ahead of the ``xy-feature`` branch in ``proj-x``, meaning there are new - upstream changes. - - We want to update ``proj-x``. This could be done with ``west pull proj-x``, - but since the ``xy-feature`` branch tracks the ``manifest-rev`` branch, we - decide to mix it up a bit with a plain Git command inside the ``proj-x`` - repository: - - .. code-block:: console - - git pull --rebase - - .. note:: - In general, do not assume that multi-repo commands are "better" where a - plain Git command will do. In particular, the multi-repo commands are not - meant to replicate every feature of the corresponding Git commands. +.. _Zephyr issue #6770: + https://github.com/zephyrproject-rtos/zephyr/issues/6770 diff --git a/doc/tools/west/west-mr-model.png b/doc/tools/west/west-mr-model.png new file mode 100755 index 0000000000000000000000000000000000000000..7c1a60fca04a6e0b99e2b649334562b9105c866e GIT binary patch literal 49639 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

i*>15<@cACfO258&J1fB&wVDCw{>F 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 literal 0 HcmV?d00001 From a523c36938ecde28a0f72b52a9af549c690e84eb Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 23 Jan 2019 08:31:06 -0700 Subject: [PATCH 009/226] scripts: add west build, flash, and debug commands West now supports a mechanism for extension commands. Use it to move the command implementations that are tightly coupled with boards and the zephyr build system back into the Zephyr repository. This patch doesn't include test cases. Those will be moved over in a subsequent patch. Signed-off-by: Marti Bolivar --- doc/tools/west/flash-debug.rst | 75 ++++++++++++++++++++++--------- doc/tools/west/west-apis.rst | 2 - doc/tools/west/west-not-found.rst | 10 ----- 3 files changed, 53 insertions(+), 34 deletions(-) delete mode 100644 doc/tools/west/west-not-found.rst diff --git a/doc/tools/west/flash-debug.rst b/doc/tools/west/flash-debug.rst index 501a3475..06f626d3 100644 --- a/doc/tools/west/flash-debug.rst +++ b/doc/tools/west/flash-debug.rst @@ -11,6 +11,14 @@ These use information stored in the CMake cache [#cmakecache]_ to flash or attach a debugger to a board supported by Zephyr. The CMake build system commands with the same names directly delegate to West. +.. Add a per-page contents at the top of the page. This page is nested + deeply enough that it doesn't have any subheadings in the main nav. + +.. only:: html + + .. contents:: + :local: + .. _west-flashing: Flashing: ``west flash`` @@ -191,37 +199,57 @@ For example, to print usage information about the ``jlink`` runner:: .. _west-runner: -Library Backend: ``west.runners`` -********************************* +Implementation Details +********************** + +The flash and debug commands are implemented as west *extension +commands*: that is, they are west commands whose source code lives +outside the west repository. Some reasons this choice was made are: + +- Their implementations are tightly coupled to the Zephyr build + system, e.g. due to their reliance on CMake cache variables. + +- Pull requests adding features to them are almost always motivated by + a corresponding change to an upstream board, so it makes sense to + put them in Zephyr to avoid needing pull requests in multiple + repositories. + +- Many users find it natural to search for their implementations in + the Zephyr source tree. -In keeping with West's :ref:`west-design-constraints`, the flash and -debug commands are wrappers around a separate library that is part of -West, and can be used by other code. +The extension commands are a thin wrapper around a package called +``runners`` (this package is also in the Zephyr tree, in +:file:`scripts/west_commands/runners`). -This library is the ``west.runners`` subpackage of West itself. The -central abstraction within this library is ``ZephyrBinaryRunner``, an -abstract class which represents *runner* objects, which can flash +The central abstraction within this library is ``ZephyrBinaryRunner``, +an abstract class which represents *runner* objects, which can flash and/or debug Zephyr programs. The set of available runners is determined by the imported subclasses of ``ZephyrBinaryRunner``. -``ZephyrBinaryRunner`` is available in the ``west.runners.core`` -module; individual runner implementations are in other submodules, -such as ``west.runners.nrfjprog``, ``west.runners.openocd``, etc. +``ZephyrBinaryRunner`` is available in the ``runners.core`` module; +individual runner implementations are in other submodules, such as +``runners.nrfjprog``, ``runners.openocd``, etc. + +Hacking and APIs +**************** Developers can add support for new ways to flash and debug Zephyr programs by implementing additional runners. To get this support into upstream Zephyr, the runner should be added into a new or existing -``west.runners`` module, and imported from -:file:`west/runner/__init__.py`. +``runners`` module, and imported from :file:`runner/__init__.py`. -.. important:: +.. note:: - Submit any changes to West to its own separate Git repository - (https://github.com/zephyrproject-rtos/west), not to the copy of - West currently present in the Zephyr tree. This copy is a temporary - measure; when West learns how to manage multiple repositories, the - copy will be removed. + The test cases in :file:`scripts/west_commands/tests` add unit test + coverage for the runners package and individual runner classes. -API documentation for the core module can be found in :ref:`west-apis`. + Please try to add tests when adding new runners. Note that if your + changes break existing test cases, CI testing on upstream pull + requests will fail. + +API Documentation for the ``runners.core`` module follows. + +.. automodule:: runners.core + :members: Doing it By Hand **************** @@ -236,8 +264,8 @@ e.g. as a source of symbol tables. By default, these West commands rebuild binaries before flashing and debugging. This can of course also be accomplished using the usual -targets provided by Zephyr's build system (in fact, that's how West -does it). +targets provided by Zephyr's build system (in fact, that's how these +commands do it). .. rubric:: Footnotes @@ -249,3 +277,6 @@ does it). .. _cmake(1): https://cmake.org/cmake/help/latest/manual/cmake.1.html + +.. _namespace package: + https://www.python.org/dev/peps/pep-0420/ diff --git a/doc/tools/west/west-apis.rst b/doc/tools/west/west-apis.rst index 7eebad3d..e4cd6c9d 100644 --- a/doc/tools/west/west-apis.rst +++ b/doc/tools/west/west-apis.rst @@ -5,6 +5,4 @@ West APIs ######### -.. automodule:: west.runners.core - :members: diff --git a/doc/tools/west/west-not-found.rst b/doc/tools/west/west-not-found.rst deleted file mode 100644 index e9ab2fbf..00000000 --- a/doc/tools/west/west-not-found.rst +++ /dev/null @@ -1,10 +0,0 @@ -:orphan: - -.. _west-apis: - -West APIs -######### - -The west APIs are not documented since west was missing during the -documentation build. - From 810f90863c7f5bd92c42392ce5da4446085484e5 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Fri, 25 Jan 2019 19:11:22 +0100 Subject: [PATCH 010/226] west: Multiple CI fixes for the topic-west branch In order to be able to merge the topic branch, we require a few fixes to CI. Signed-off-by: Anas Nashif Signed-off-by: Carles Cufi --- doc/tools/west/repo-tool.rst | 4 ++-- doc/tools/west/west-mr-model.png | Bin 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100755 => 100644 doc/tools/west/west-mr-model.png diff --git a/doc/tools/west/repo-tool.rst b/doc/tools/west/repo-tool.rst index 7054698e..a200b904 100644 --- a/doc/tools/west/repo-tool.rst +++ b/doc/tools/west/repo-tool.rst @@ -96,7 +96,7 @@ in detail: replace submodule definitions - Does not support continuous tracking of the latest ``HEAD`` in external repositories (*R4*) - - Requires hardcoding of the paths/locations of the external repositories + - Requires hardcoding of the paths/locations of the external repositories Finally, please see :ref:`west-history` for the motivations behind using a single tool for both multi-repository management as well as building, debugging @@ -271,7 +271,7 @@ manifest), the following commands will clone/update projects. the existing clone, without modifying it. For example, ``west init -l path/to/zephyr`` is useful if you already have cloned the zephyr repository in the past using Git and now want to initialize a west - installation around it. + installation around it. If you however want to initialize an installation directly from the remote repository, you have the option to specify its URL using the ``-m`` switch and/or its revision with the ``--mr`` one. For example, invoking west with: diff --git a/doc/tools/west/west-mr-model.png b/doc/tools/west/west-mr-model.png old mode 100755 new mode 100644 From 42566f703b282fbd271200055d23a4b6797f762b Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Sat, 26 Jan 2019 22:12:48 +0100 Subject: [PATCH 011/226] doc: west: Misc formatting fixes Miscellaneous formatting fixes in the west documentation. Signed-off-by: Carles Cufi --- doc/tools/west/index.rst | 9 +++-- doc/tools/west/repo-tool.rst | 67 +++++++++++++++---------------- doc/tools/west/west-mr-model.png | Bin 49639 -> 67684 bytes 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/doc/tools/west/index.rst b/doc/tools/west/index.rst index c7b80e79..f87d4ff3 100644 --- a/doc/tools/west/index.rst +++ b/doc/tools/west/index.rst @@ -1,7 +1,7 @@ .. _west: -West -#### +West (Zephyr's meta-tool) +######################### The Zephyr project includes a swiss-army knife command line tool named ``west`` (Zephyr is an English name for the Latin @@ -137,8 +137,9 @@ like this: ├── .west/ │   ├── config │   └── west/ - └── zephyr/ -    └── west.yml + ├── zephyr/ + │   └── west.yml + └── ... ``west init`` also creates a configuration file :file:`.west/config` that stores configuration metadata about the west installation. diff --git a/doc/tools/west/repo-tool.rst b/doc/tools/west/repo-tool.rst index a200b904..74ec0ef0 100644 --- a/doc/tools/west/repo-tool.rst +++ b/doc/tools/west/repo-tool.rst @@ -8,7 +8,7 @@ Introduction West includes a set of commands for working with projects composed of multiple Git repositories (a *multi-repo*), similar to `Git Submodules -` and Google's `repo +`_ and Google's `repo `_ tool. The rest of this page introduces multi-repo concepts and gives an overview of @@ -20,7 +20,6 @@ the multi-repo commands, along with an example workflow. See The multi-repo commands are meant to augment Git in minor ways for multi-repo work, not replace it. For tasks that aren't multi-repo-related, use plain Git commands. - This page explains what the west multi-repo commands do behind the scenes. Requirements @@ -33,13 +32,13 @@ instead develop a new one, do belong here. At the most fundamental level, the requirements for a transition to multiple repositories in the Zephyr Project are: -* *R1*: Keep externally maintained code outside of the main repository -* *R2*: Provide a tool that both Zephyr users and distributors can make use of - to benefit from and extend the functionality above -* *R3*: Allow overriding or removing repositories without having to make changes - to the zephyr repository -* *R4*: Support both continuous tracking and commit-based (bisectable) project - updating +* **R1**: Keep externally maintained code outside of the main repository +* **R2**: Provide a tool that both Zephyr users and distributors can make use of + to benefit from and extend the functionality above +* **R3**: Allow overriding or removing repositories without having to make changes + to the zephyr repository +* **R4**: Support both continuous tracking and commit-based (bisectable) project + updating Topologies supported ******************** @@ -47,29 +46,29 @@ Topologies supported The requirements above lead us to the three main source code organization topologies that we intend to address with west: -#. *T1* Star topology with zephyr as the manifest repository: +* **T1**: Star topology with zephyr as the manifest repository: - - The zephyr repository acts as the central repository and includes a - complete list of projects in itself - - Default (upstream) configuration - - Analogy with existing mechanisms: Git submodules with zephyr as the - superproject + - The zephyr repository acts as the central repository and includes a + complete list of projects in itself + - Default (upstream) configuration + - Analogy with existing mechanisms: Git submodules with zephyr as the + superproject -#. *T2* Star topology with an application repository as the manifest repository +* **T2**: Star topology with an application repository as the manifest repository - - The application repository acts as the central repository and includes a - complete list of projects in itself - - Useful for downstream distributions focused in a single application - repository - - Analogy with existing mechanisms: Git submodules with the application as - the superproject, zephyr as a submodule + - The application repository acts as the central repository and includes a + complete list of projects in itself + - Useful for downstream distributions focused in a single application + repository + - Analogy with existing mechanisms: Git submodules with the application as + the superproject, zephyr as a submodule -#. *T3* Forest topology with a set of trees all at the same level +* **T3**: Forest topology with a set of trees all at the same level - - A dedicated manifest repository contains only a list of repositories - - Useful for downstream distributions that track the latest ``HEAD`` on all - repositories - - Analogy with existing mechanisms: Google repo-based distribution + - A dedicated manifest repository contains only a list of repositories + - Useful for downstream distributions that track the latest ``HEAD`` on all + repositories + - Analogy with existing mechanisms: Google repo-based distribution Rationale for a custom tool *************************** @@ -86,16 +85,16 @@ in detail: - Does not play well with Windows - It is poorly documented and maintained - It does not fully support a set of bisectable repositories without - additional intervention (*R4*) + additional intervention (**R4**) * Git submodules - - Does not fully support *R1*, since the externally maintained repositories + - Does not fully support **R1**, since the externally maintained repositories would still need to be inside the main zephyr Git tree - - Does not support *R3*. Downstream copies would need to either delete or + - Does not support **R3**. Downstream copies would need to either delete or replace submodule definitions - Does not support continuous tracking of the latest ``HEAD`` in external - repositories (*R4*) + repositories (**R4**) - Requires hardcoding of the paths/locations of the external repositories Finally, please see :ref:`west-history` for the motivations behind using a @@ -110,9 +109,9 @@ Model Manifest ======== -A *manifest* is a `YAML `_ file that, at a minimum, gives the -URL and revision for each project repository in the multi-repo (each *project*). -The manifest is stored in the *manifest repository* and is named :file:`west.yml`. +A **manifest** is a `YAML `_ file that, at a minimum, gives the +URL and revision for each project repository in the multi-repo (each **project**). +The manifest is stored in the **manifest repository** and is named :file:`west.yml`. The format of the west manifest is described by a `pykwalify `_ schema, found `here diff --git a/doc/tools/west/west-mr-model.png b/doc/tools/west/west-mr-model.png index 7c1a60fca04a6e0b99e2b649334562b9105c866e..ddbfdb62a6fcd398e4e25dcfd92ab8edb56f39b1 100644 GIT binary patch literal 67684 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 yhp;QBW|^Mvv;)s{G{!KUtsM*FG`V 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

i*>15<@cACfO258&J1fB&wVDCw{>F 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 From 52bbe2a886a6ef81282d266eef7f4fa33dfb018c Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Sun, 27 Jan 2019 17:52:43 +0100 Subject: [PATCH 012/226] doc: west: Do not fail doc build if west not used In case west is not present or was not used to initialize the local zephyr repository, avoid failing the documentation build by including a placeholder file. Signed-off-by: Carles Cufi --- doc/tools/west/flash-debug.rst | 6 ++---- doc/tools/west/west-apis.rst | 2 ++ doc/tools/west/west-not-found.rst | 10 ++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 doc/tools/west/west-not-found.rst diff --git a/doc/tools/west/flash-debug.rst b/doc/tools/west/flash-debug.rst index 06f626d3..6567d053 100644 --- a/doc/tools/west/flash-debug.rst +++ b/doc/tools/west/flash-debug.rst @@ -246,10 +246,8 @@ upstream Zephyr, the runner should be added into a new or existing changes break existing test cases, CI testing on upstream pull requests will fail. -API Documentation for the ``runners.core`` module follows. - -.. automodule:: runners.core - :members: +API Documentation for the ``runners.core`` module can be found in +:ref:`west-apis`. Doing it By Hand **************** diff --git a/doc/tools/west/west-apis.rst b/doc/tools/west/west-apis.rst index e4cd6c9d..2a855cfe 100644 --- a/doc/tools/west/west-apis.rst +++ b/doc/tools/west/west-apis.rst @@ -5,4 +5,6 @@ West APIs ######### +.. automodule:: runners.core + :members: diff --git a/doc/tools/west/west-not-found.rst b/doc/tools/west/west-not-found.rst new file mode 100644 index 00000000..1881f5c0 --- /dev/null +++ b/doc/tools/west/west-not-found.rst @@ -0,0 +1,10 @@ +:orphan: + +.. _west-apis: + +West APIs +######### + +The west APIs are not documented since either west was missing or the zephyr +repository was not initialized using west during the documentation build. + From ec765b967499b5651ace345b7385fd758c3239d8 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 30 Jan 2019 01:40:55 -0700 Subject: [PATCH 013/226] doc: incremental improvements to west docs Reorganize the entry page so it's not as jarring of a landing by reorganizing the content a bit in the rest of the toctree. This makes it easier to read more progressively without having to jump around as much. Signed-off-by: Marti Bolivar --- doc/tools/west/index.rst | 283 +++----------------------------- doc/tools/west/planned.rst | 19 +++ doc/tools/west/repo-tool.rst | 135 ++++++++++++++- doc/tools/west/why.rst | 77 +++++++++ doc/tools/west/without-west.rst | 46 ++++++ 5 files changed, 292 insertions(+), 268 deletions(-) create mode 100644 doc/tools/west/planned.rst create mode 100644 doc/tools/west/why.rst create mode 100644 doc/tools/west/without-west.rst diff --git a/doc/tools/west/index.rst b/doc/tools/west/index.rst index f87d4ff3..ef17534b 100644 --- a/doc/tools/west/index.rst +++ b/doc/tools/west/index.rst @@ -8,278 +8,41 @@ named ``west`` (Zephyr is an English name for the Latin `Zephyrus `_, the ancient Greek god of the west wind). -West is developed in its own `repository on GitHub`_. +West is used upstream to obtain the source code for the Zephyr project and can +also be used to build, debug, and flash applications. It is developed in its +own `repository on GitHub`_. The source code retrieval features include a +multiple repository management system with features inspired by Google's Repo +tool and Git submodules. -West is used to obtain the source code for the Zephyr project and can also be -used to build, debug, and flash applications. +West is also pluggable: you can write your own west "extension commands" to add +additional features. Extension commands can be in any directory in your +installation; they don't have to be defined in the zephyr or west repositories. -.. _west-history: - -History and motivation -********************** - -West was added to the Zephyr project to fulfill two fundamental requirements: - -* The ability to work with multiple Git repositories -* The ability to provide a user-friendly command-line interface to the Zephyr - build system and debug mechanisms - -During the development of west, a set of :ref:`west-design-constraints` were -identified to avoid the common pitfalls of tools of this kind. - -Multiple Git Repositories -========================= - -Zephyr intends to provide all required building blocks needed to deploy complex -IoT applications. This in turn means that the Zephyr project is much more than -an RTOS kernel, and is instead a collection of components that work together. -In this context, there are a few reasons to work with multiple Git -repositories in a standardized manner within the project: - -* Clean separation of Zephyr original code and imported projects and libraries -* Avoidance of license incompatibilities between original and imported code -* Reduction in size and scope of the core Zephyr codebase, with additional - repositories containing optional components instead of being imported - directly into the tree -* Safety and security certifications -* Enforcement of modularization of the components -* Out-of-tree development based on subsets of the supported boards and SoCs - -See :ref:`west-multi-repo` for a detailed explanation of west's handling of -multiple repository management. - -Command-line interface -====================== - -Zephyr uses CMake as its build system management tool, as described in -:ref:`application`. -While CMake is a very powerful system and language, its two-stage nature -as a build system generator makes it non-trivial to present the user with -a consistent set of command-line switches and options that enable advanced -usage of the build tool ultimately responsible for building, flashing, and -debugging the application. -West was introduced to unify and streamline the developer's experience when -working with Zephyr. It is very important to note that west does not -replace the CMake-based build system, but directly uses it and augments it. - -See :ref:`west-flash-debug` for a detailed explanation of the flash and debug -command-line interface exposed by west. - -.. _west-struct: - -Structure -********* - -West structure -============== - -West is downloaded and installed on a system in two stages: - -* Bootstrapper: Installed using ``pip``, implements ``west init`` -* Installation: Installed using ``west init``, implements all other commands - -Additional information about the two distinct parts of west can be found in -the corresponding sections below. - -Repository structure -==================== - -Beyond west itself, the actual code repositories that west works with -are the following: - -* Manifest repository: Cloned by ``west init``, and managed afterward with Git - by the user. Contains the list of projects in the manifest :file:`west.yml` - file. In the case of upstream Zephyr, the zephyr repository is the manifest - repository. -* Projects: Cloned and managed by ``west update``. Listed in the manifest file. - -See :ref:`west-mr-model` for more information on the multi-repository layout. - -Bootstrapper -============ - -The bootstrapper module is distributed using `PyPi`_ (i.e. :file:`pip`) and it's -placed in the user's ``PATH`` becoming the only entry point to west. -It implements a single command: ``west init``. This command needs to be run -first to use the rest of functionality included in ``west``. The command -``west init`` will do the following: - -* Clone west itself in a :file:`.west/west` folder -* Clone the manifest repository in the folder specified by the manifest file's - (:file:`west.yml`) ``self.path`` section. Additional information - on the manifest can be found in the :ref:`west-multi-repo` section) - -Once ``west init`` has been run, the bootstrapper will delegate the handling of -any west commands other than ``init`` to the cloned west installation. - -This means that there is a single bootstrapper instance installed at any time -(unless you use virtual environments), which can then be used to initialize as -many installations as needed. - -.. _west-struct-installation: - -Installation -============ - -A west installation is the result of running ``west init`` in an existing -folder, or ``west init `` to create and initialize a folder. As -described on the previous section, an installation always includes a special -:file:`.west/` folder that contains a clone of west itself, as well as a local -clone of the manifest repository (``zephyr`` in the default upstream case). -Additionally, and once ``west update`` has been run, the installation will also -contain a clone of any repositories listed in the manifest. The directory tree -layout of an installation using the default Zephyr manifest therefore looks -like this: - -.. code-block:: console - - └── zephyrproject/ - ├── .west/ - │   ├── config - │   └── west/ - ├── zephyr/ - │   └── west.yml - └── ... - -``west init`` also creates a configuration file :file:`.west/config` -that stores configuration metadata about the west installation. - -To learn more about west's handling of multiple repositories refer to -:ref:`west-multi-repo`. - -The west bootstrapper delegates handling for all commands except ``init`` to -the installation in :file:`.west/west`. - -Usage -***** - -West's usage is similar to Git's: general options are followed by a -command, which may also take options and arguments:: +Like :program:`git` and :program:`docker`, the top-level :program:`west` +command takes some options, a sub-command to run, and then options specific to +that sub-command:: west [common-opts] [command-opts] [] -Usage guides for specific groups of subcommands are in the following -pages. +After you've :ref:`created a Zephyr installation using west `, +you can run ``west --help`` (or ``west -h`` for short) to get top-level help on +west's built-in commands along with any extension commands available in your +installation. + +The following pages describe how to use west, and provide additional context +about the tool. .. toctree:: :maxdepth: 1 repo-tool.rst flash-debug.rst + why.rst + without-west.rst + planned.rst -(This list will expand as additional features are developed.) - -Planned Features -**************** - -Additional features are under development for future versions of -Zephyr: - -- Running Zephyr in emulation. - -- Bootloader integration: bootloader-aware image building, signing, - and flashing, as well as building and flashing the bootloader itself. - -- Additional multiple repository support: fetching and updating repositories - that integrate with Zephyr, such as `MCUboot`_, `OpenThread`_ and others. - - -.. _west-design-constraints: - -Design Constraints -****************** - -West is: - -- **Optional**: it is always *possible* to drop back to "raw" - command-line tools, i.e. use Zephyr without using west (although west itself - might need to be installed and accessible to the build system). It may not - always be *convenient* to do so, however. (If all of west's features - were already conveniently available, there would be no reason to - develop it.) - -- **Compatible with CMake**: building, flashing and debugging, and - emulator support will always remain compatible with direct use of - CMake. - -- **Cross-platform**: West is written in Python 3, and works on all - platforms supported by Zephyr. - -- **Usable as a Library**: whenever possible, west features are - implemented as libraries that can be used standalone in other - programs, along with separate command line interfaces that wrap - them. West itself is a Python package named ``west``; its libraries - are implemented as subpackages. - -- **Conservative about features**: no features will be accepted without - strong and compelling motivation. - -- **Clearly specified**: West's behavior in cases where it wraps other - commands is clearly specified and documented. This enables - interoperability with third party tools, and means Zephyr developers - can always find out what is happening "under the hood" when using west. - -See `Zephyr issue #6205`_ and for more details and -discussion. - -.. _no-west: - -Using Zephyr without west -************************* - -There are many valid usecases to avoid using a meta-tool such as west which has -been custom-designed for a particular project and its requirements. -This section applies to Zephyr users who fall into one or more of these -categories: - -- Already use a multi-repository management system (for example Google repo) - -- Do not need additional functionality beyond compiling and linking - -In order to obtain the Zephyr source code and build it without the help of -west you will need to manually clone the repositories listed in the -`manifest file`_ one by one, at the path indicated in it. - -.. code-block:: console - - mkdir zephyrproject - cd zephyrproject - git clone https://github.com/zephyrproject-rtos/zephyr - # clone additional repositories listed in the manifest file - -If you want to manage Zephyr's repositories without west but still need to -use west's additional functionality (flashing, debugging, etc.) it is possible -to do so by manually creating an installation: - -.. code-block:: console - - # cd into zephyrproject if not already there - git clone https://github.com/zephyrproject-rtos/west.git - echo [manifest] > .west/config - echo path = zephyr >> .west/config - -After that, and in order for ``ninja`` to be able to invoke ``west`` you must -specify the west directory. This can be done as: - -- Set the environment variable ``WEST_DIR`` to point to the directory where - ``west`` was cloned -- Specify ``WEST_DIR`` when running ``cmake``, e.g. - ``cmake -DWEST_DIR= ...`` +For details on west's Python APIs (including APIs provided by extensions in the +zephyr), see :ref:`west-apis`. .. _repository on GitHub: https://github.com/zephyrproject-rtos/west - -.. _PyPi: - https://pypi.org/project/west/ - -.. _MCUboot: - https://mcuboot.com/ - -.. _OpenThread: - https://openthread.io/ - -.. _Zephyr issue #6205: - https://github.com/zephyrproject-rtos/zephyr/issues/6205 - -.. _manifest file: - https://github.com/zephyrproject-rtos/zephyr/blob/master/west.yml diff --git a/doc/tools/west/planned.rst b/doc/tools/west/planned.rst new file mode 100644 index 00000000..3b4d5658 --- /dev/null +++ b/doc/tools/west/planned.rst @@ -0,0 +1,19 @@ +Planned Features +================ + +Additional west features are under development for future versions of +Zephyr: + +- Running Zephyr in emulation. + +- Bootloader integration: bootloader-aware image building, signing, + and flashing, as well as building and flashing the bootloader itself. + +- Additional multiple repository support: fetching and updating repositories + that integrate with Zephyr, such as `MCUboot`_, `OpenThread`_ and others. + +.. _MCUboot: + https://mcuboot.com/ + +.. _OpenThread: + https://openthread.io/ diff --git a/doc/tools/west/repo-tool.rst b/doc/tools/west/repo-tool.rst index 74ec0ef0..ebe0bd2c 100644 --- a/doc/tools/west/repo-tool.rst +++ b/doc/tools/west/repo-tool.rst @@ -1,18 +1,19 @@ .. _west-multi-repo: -West and Multi-repository -######################### +Multiple Repository Management +############################## Introduction ************ West includes a set of commands for working with projects composed of multiple -Git repositories (a *multi-repo*), similar to `Git Submodules +Git repositories installed under a common parent directory (a *west +installation*), similar to how `Git Submodules `_ and Google's `repo -`_ tool. +`_ work. -The rest of this page introduces multi-repo concepts and gives an overview of -the multi-repo commands, along with an example workflow. See +The rest of this page introduces these multi-repo concepts and gives an +overview of the associated west commands, along with an example workflow. See `Zephyr issue #6770`_ for additional background and discussion. .. note:: @@ -22,6 +23,37 @@ the multi-repo commands, along with an example workflow. See use plain Git commands. This page explains what the west multi-repo commands do behind the scenes. +A west installation is the result of running the ``west init`` command to +either create a new installation or convert a standalone zephyr repository into +a multi-repo installation. When using upstream Zephyr, it looks like this: + +.. code-block:: console + + └── zephyrproject/ + ├── .west/ + │   ├── config + │   └── west/ + ├── zephyr/ + │   └── west.yml + ├── a-project + └── ... + +Above, :file:`zephyrproject` is the name of the west installation's common +parent directory, and :file:`a-project` is another project managed by west in +the installation. The file :file:`.west/config` is the installation's west +configuration file. The directory :file:`.west/west` is a clone of the west +repository itself; more details on why that is needed are given below. + +Every west installation contains a *manifest repository*, which is a Git +repository containing a file named :file:`west.yml`. This file, along with +what's in :file:`.west`, controls the installation's behavior. In the above +example, zephyr is the manifest repository. However, as you'll see below, any +repository in an installation can be the manifest repository; it doesn't have +to be zephyr. However, every installation has exactly one manifest repository; +its location is specified in :file:`.west/config`. Alongside the manifest +repository are *projects*, which are Git repositories specified by +:file:`west.yml`. + Requirements ************ @@ -101,6 +133,91 @@ Finally, please see :ref:`west-history` for the motivations behind using a single tool for both multi-repository management as well as building, debugging and flashing. + +.. _west-struct: + +Structure +********* + +West structure +============== + +West is currently downloaded and installed on a system in the following stages: + +* Bootstrapper: Installed using ``pip``, implements ``west init`` +* Installation: Installed using ``west init``, implements built-in multi-repo + commands +* Extension commands: Installed using ``west update``, parses the manifest + in the west installation for additional commands + +.. note:: + + The separation between the "bootstrapper" and "installation" pieces is + inspired by the Google Repo tool, but it's a temporary structure for + convenience. In the future, the two will be merged. This will lessen the + complexity of the design and make it easier to write and debug extension + commands. + +Repository structure +==================== + +Beyond west itself, the actual code repositories that west works with +are the following: + +* Manifest repository: Cloned by ``west init``, and managed afterward with Git + by the user. Contains the list of projects in the manifest file + :file:`west.yml`. In the case of upstream Zephyr, the zephyr repository is + the manifest repository. +* Projects: Cloned and managed by ``west update``. Listed in the manifest file. + +Bootstrapper +============ + +The bootstrapper module is distributed using `PyPI`_ and installed using +:file:`pip`. A launcher named ``west`` is placed by :file:`pip` in the user's +``PATH``. This the only entry point to west. It implements a single command: +``west init``. This command needs to be run first to use the rest of +functionality included in ``west``, by creating a west installation. The +command ``west init`` does the following: + +* Clone west itself in a :file:`.west/west` folder in the installation +* Clone the manifest repository in the folder specified by the manifest file's + (:file:`west.yml`) ``self.path`` section. Additional information + on the manifest can be found in the :ref:`west-multi-repo` section) + +Once ``west init`` has been run, the bootstrapper will delegate the handling of +any west commands other than ``init`` to the cloned west installation. + +This means that there is a single bootstrapper instance installed at any time +(unless you use virtual environments), which can then be used to initialize as +many installations as needed. + +.. _west-struct-installation: + +Installation +============ + +A west installation, as describe above, contains a clone of the west repository +in :file:`.west/west`. The clone of west in the installation is where the +built-in multi-repo command implementations are currently provided. + +When running a west command, the bootstrapper delegates handling for all +commands except ``init`` to the :file:`.west/west` repository in the current +installation. + +Extension Commands +================== + +The west manifest file (more about which below) allows any repository in the +installation to provide additional west commands (the flash and debug commands +use this mechanism; they are defined in the west repository). Every repository +which includes extension commands must provide a YAML file which configures the +names of the commands, the Python files that implement them, and other +metadata. + +The locations of these YAML files throughout the installation are specified in +the manifest, which you'll read about next. + .. _west-mr-model: Model @@ -113,8 +230,7 @@ A **manifest** is a `YAML `_ file that, at a minimum, gives th URL and revision for each project repository in the multi-repo (each **project**). The manifest is stored in the **manifest repository** and is named :file:`west.yml`. -The format of the west manifest is described by a `pykwalify -`_ schema, found `here +The format of the west manifest is described by a pykwalify schema, `manifest-schema.yml `_. A west-based Zephyr installation has a special manifest repository. This @@ -327,5 +443,8 @@ These commands perform miscellaneous functions. that fetches upstream data is run (this behavior can be suppressed for the duration of a single command by passing ``--no-update``). +.. _PyPI: + https://pypi.org/project/west/ + .. _Zephyr issue #6770: https://github.com/zephyrproject-rtos/zephyr/issues/6770 diff --git a/doc/tools/west/why.rst b/doc/tools/west/why.rst new file mode 100644 index 00000000..ecfa0395 --- /dev/null +++ b/doc/tools/west/why.rst @@ -0,0 +1,77 @@ +.. _west-history: + +History and Motivation +###################### + +West was added to the Zephyr project to fulfill two fundamental requirements: + +* The ability to work with multiple Git repositories +* The ability to provide a user-friendly command-line interface to the Zephyr + build system and debug mechanisms + +Additionally, it was desired that west be easily extensible by +downstream users. + +During the development of west, a set of :ref:`west-design-constraints` were +identified to avoid the common pitfalls of tools of this kind. + +Multiple Git Repositories +************************* + +Zephyr intends to provide all required building blocks needed to deploy complex +IoT applications. This in turn means that the Zephyr project is much more than +an RTOS kernel, and is instead a collection of components that work together. +In this context, there are a few reasons to work with multiple Git +repositories in a standardized manner within the project: + +* Clean separation of Zephyr original code and imported projects and libraries +* Avoidance of license incompatibilities between original and imported code +* Reduction in size and scope of the core Zephyr codebase, with additional + repositories containing optional components instead of being imported + directly into the tree +* Safety and security certifications +* Enforcement of modularization of the components +* Out-of-tree development based on subsets of the supported boards and SoCs + +See :ref:`west-multi-repo` for a detailed explanation of west's handling of +multiple repository management. + +.. _west-design-constraints: + +Design Constraints +****************** + +West is: + +- **Optional**: it is always *possible* to drop back to "raw" + command-line tools, i.e. use Zephyr without using west (although west itself + might need to be installed and accessible to the build system). It may not + always be *convenient* to do so, however. (If all of west's features + were already conveniently available, there would be no reason to + develop it.) + +- **Compatible with CMake**: building, flashing and debugging, and + emulator support will always remain compatible with direct use of + CMake. + +- **Cross-platform**: West is written in Python 3, and works on all + platforms supported by Zephyr. + +- **Usable as a Library**: whenever possible, west features are + implemented as libraries that can be used standalone in other + programs, along with separate command line interfaces that wrap + them. West itself is a Python package named ``west``; its libraries + are implemented as subpackages. + +- **Conservative about features**: no features will be accepted without + strong and compelling motivation. + +- **Clearly specified**: West's behavior in cases where it wraps other + commands is clearly specified and documented. This enables + interoperability with third party tools, and means Zephyr developers + can always find out what is happening "under the hood" when using west. + +See `Zephyr issue #6205`_ and for more details and discussion. + +.. _Zephyr issue #6205: + https://github.com/zephyrproject-rtos/zephyr/issues/6205 diff --git a/doc/tools/west/without-west.rst b/doc/tools/west/without-west.rst new file mode 100644 index 00000000..878fd360 --- /dev/null +++ b/doc/tools/west/without-west.rst @@ -0,0 +1,46 @@ +.. _no-west: + +Using Zephyr without west +######################### + +There are many valid usecases to avoid using a meta-tool such as west which has +been custom-designed for a particular project and its requirements. +This section applies to Zephyr users who fall into one or more of these +categories: + +- Already use a multi-repository management system (for example Google repo) + +- Do not need additional functionality beyond compiling and linking + +In order to obtain the Zephyr source code and build it without the help of +west you will need to manually clone the repositories listed in the +`manifest file`_ one by one, at the path indicated in it. + +.. code-block:: console + + mkdir zephyrproject + cd zephyrproject + git clone https://github.com/zephyrproject-rtos/zephyr + # clone additional repositories listed in the manifest file + +If you want to manage Zephyr's repositories without west but still need to +use west's additional functionality (flashing, debugging, etc.) it is possible +to do so by manually creating an installation: + +.. code-block:: console + + # cd into zephyrproject if not already there + git clone https://github.com/zephyrproject-rtos/west.git + echo [manifest] > .west/config + echo path = zephyr >> .west/config + +After that, and in order for ``ninja`` to be able to invoke ``west`` you must +specify the west directory. This can be done as: + +- Set the environment variable ``WEST_DIR`` to point to the directory where + ``west`` was cloned +- Specify ``WEST_DIR`` when running ``cmake``, e.g. + ``cmake -DWEST_DIR= ...`` + +.. _manifest file: + https://github.com/zephyrproject-rtos/zephyr/blob/master/west.yml From 5a58f375f1f9bfa9700b85b368f8fbe4498abd9c Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 31 Jan 2019 16:00:52 -0700 Subject: [PATCH 014/226] doc: without-west.rst: fixes for correctness Fix some correctness issues. Signed-off-by: Marti Bolivar --- doc/tools/west/without-west.rst | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/doc/tools/west/without-west.rst b/doc/tools/west/without-west.rst index 878fd360..ce38c068 100644 --- a/doc/tools/west/without-west.rst +++ b/doc/tools/west/without-west.rst @@ -21,7 +21,8 @@ west you will need to manually clone the repositories listed in the mkdir zephyrproject cd zephyrproject git clone https://github.com/zephyrproject-rtos/zephyr - # clone additional repositories listed in the manifest file + # clone additional repositories listed in the manifest file, + # and check out the specified revisions If you want to manage Zephyr's repositories without west but still need to use west's additional functionality (flashing, debugging, etc.) it is possible @@ -30,17 +31,20 @@ to do so by manually creating an installation: .. code-block:: console # cd into zephyrproject if not already there - git clone https://github.com/zephyrproject-rtos/west.git - echo [manifest] > .west/config - echo path = zephyr >> .west/config + git clone https://github.com/zephyrproject-rtos/west.git .west/west -After that, and in order for ``ninja`` to be able to invoke ``west`` you must -specify the west directory. This can be done as: +Then create a file :file:`.west/config` with the following contents: -- Set the environment variable ``WEST_DIR`` to point to the directory where - ``west`` was cloned -- Specify ``WEST_DIR`` when running ``cmake``, e.g. - ``cmake -DWEST_DIR= ...`` +.. code-block:: none + + [manifest] + path = zephyr + +After that, and in order for ``ninja`` to be able to invoke ``west`` +to flash and debug, you must specify the west directory. This can be +done by setting the environment variable ``WEST_DIR`` to point to +:file:`zephyrproject/.west/west` before running CMake to set up a +build directory. .. _manifest file: https://github.com/zephyrproject-rtos/zephyr/blob/master/west.yml From 142932e6d55289bfdf03bc926189adb50cc16c3c Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 2 Feb 2019 11:06:11 -0500 Subject: [PATCH 015/226] doc: introduce final structure Move guides and APIs into separate directories and cleanup naming introducing index files rather than named section files. Signed-off-by: Anas Nashif --- doc/{tools => guides}/west/flash-debug.rst | 0 doc/{tools => guides}/west/index.rst | 0 doc/{tools => guides}/west/planned.rst | 0 doc/{tools => guides}/west/repo-tool.rst | 0 doc/{tools => guides}/west/west-apis.rst | 0 doc/{tools => guides}/west/west-mr-model.png | Bin doc/{tools => guides}/west/west-not-found.rst | 0 doc/{tools => guides}/west/why.rst | 0 doc/{tools => guides}/west/without-west.rst | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename doc/{tools => guides}/west/flash-debug.rst (100%) rename doc/{tools => guides}/west/index.rst (100%) rename doc/{tools => guides}/west/planned.rst (100%) rename doc/{tools => guides}/west/repo-tool.rst (100%) rename doc/{tools => guides}/west/west-apis.rst (100%) rename doc/{tools => guides}/west/west-mr-model.png (100%) rename doc/{tools => guides}/west/west-not-found.rst (100%) rename doc/{tools => guides}/west/why.rst (100%) rename doc/{tools => guides}/west/without-west.rst (100%) diff --git a/doc/tools/west/flash-debug.rst b/doc/guides/west/flash-debug.rst similarity index 100% rename from doc/tools/west/flash-debug.rst rename to doc/guides/west/flash-debug.rst diff --git a/doc/tools/west/index.rst b/doc/guides/west/index.rst similarity index 100% rename from doc/tools/west/index.rst rename to doc/guides/west/index.rst diff --git a/doc/tools/west/planned.rst b/doc/guides/west/planned.rst similarity index 100% rename from doc/tools/west/planned.rst rename to doc/guides/west/planned.rst diff --git a/doc/tools/west/repo-tool.rst b/doc/guides/west/repo-tool.rst similarity index 100% rename from doc/tools/west/repo-tool.rst rename to doc/guides/west/repo-tool.rst diff --git a/doc/tools/west/west-apis.rst b/doc/guides/west/west-apis.rst similarity index 100% rename from doc/tools/west/west-apis.rst rename to doc/guides/west/west-apis.rst diff --git a/doc/tools/west/west-mr-model.png b/doc/guides/west/west-mr-model.png similarity index 100% rename from doc/tools/west/west-mr-model.png rename to doc/guides/west/west-mr-model.png diff --git a/doc/tools/west/west-not-found.rst b/doc/guides/west/west-not-found.rst similarity index 100% rename from doc/tools/west/west-not-found.rst rename to doc/guides/west/west-not-found.rst diff --git a/doc/tools/west/why.rst b/doc/guides/west/why.rst similarity index 100% rename from doc/tools/west/why.rst rename to doc/guides/west/why.rst diff --git a/doc/tools/west/without-west.rst b/doc/guides/west/without-west.rst similarity index 100% rename from doc/tools/west/without-west.rst rename to doc/guides/west/without-west.rst From f18b821110c7b26d163904e96b67097a0c6d3e3f Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 7 Feb 2019 18:16:49 +0100 Subject: [PATCH 016/226] doc: west: Document west build Document the `west build` command in the section corresponding to the west commands that deal with the CMake cache, which is now named "Building, flashing and debugging" for consistency. Signed-off-by: Carles Cufi --- ...{flash-debug.rst => build-flash-debug.rst} | 99 +++++++++++++++++-- doc/guides/west/index.rst | 2 +- 2 files changed, 92 insertions(+), 9 deletions(-) rename doc/guides/west/{flash-debug.rst => build-flash-debug.rst} (70%) diff --git a/doc/guides/west/flash-debug.rst b/doc/guides/west/build-flash-debug.rst similarity index 70% rename from doc/guides/west/flash-debug.rst rename to doc/guides/west/build-flash-debug.rst index 6567d053..b3891cad 100644 --- a/doc/guides/west/flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -1,15 +1,18 @@ -.. _west-flash-debug: +.. _west-build-flash-debug: -Flashing and Debugging -###################### +Building, Flashing and Debugging +################################ -West provides three commands for running and interacting with Zephyr -programs running on a board: ``flash``, ``debug``, and -``debugserver``. +West provides 5 commands for building, flashing, and interacting with Zephyr +programs running on a board: ``build``, ``flash``, ``debug``, ``debugserver`` +and ``attach``. These use information stored in the CMake cache [#cmakecache]_ to -flash or attach a debugger to a board supported by Zephyr. The CMake -build system commands with the same names directly delegate to West. +flash or attach a debugger to a board supported by Zephyr. The exception is +starting a clean build (i.e. with no previous artifacts) which will in fact +run CMake thus creating the corresponding cache. +The CMake build system commands with the same names (i.e. all but ``build``) +directly delegate to West. .. Add a per-page contents at the top of the page. This page is nested deeply enough that it doesn't have any subheadings in the main nav. @@ -19,6 +22,76 @@ build system commands with the same names directly delegate to West. .. contents:: :local: +.. _west-building: + +Building: ``west build`` +************************ + +.. tip:: Run ``west build -h`` for additional help. + +The ``build`` command allows you to build any source tree from any directory +in your file system, placing the build results in a folder of your choice. + +In its simplest form, the command can be run by navigating to the root folder +(i.e. the folder containing a file:`CMakeLists.txt` file) of the Zephyr +application of your choice and running:: + + west build -b + +Where ```` is the name of the board you want to build for. This is +exactly the same name you would supply to CMake if you were to invoke it with: +``cmake -DBOARD=``. +A build folder named :file:`build` (default name) will be created and the +build output will be placed in it. + +To specify the build directory, use ``--build-dir`` (or ``-d``):: + + west build -b --build-dir path/to/build/directory + +Since the build directory defaults to :file:`build`, if you do not specify +a build directory but a folder named file:`build` is present, that will be used, +allowing you to incrementally build from outside the file:`build` folder with +no additional parameters. + +.. note:: + The ``-b `` parameter is only required when there is no CMake cache + present at all, usually when you are building from scratch or creating a + brand new build directory. After that you can rebuild (even with additional + parameters) without having to specify the board again. If you're unsure + whether ``-b`` is required, just try leaving it out. West will print an + error if the option is required and was not given. + +To specify the source directory, use ``--source-dir`` (or ``-s``):: + + west build -b --source-dir path/to/source/directory + +Additionally you can specify the build system target using the ``--target`` +(or ``-t``) option. For example, to run the ``clean`` target:: + + west build -t clean + +You can list all targets with ``ninja help`` (or ``west build -t help``) inside +the build folder. + + +Finally, you can add additional arguments to the CMake invocation performed by +``west build`` by supplying additional parameters (after a ``--``) to the +command. For example, to use the Unix Makefiles CMake generator instead of +Ninja (which ``west build`` uses by default), run:: + + west build -- -G'Unix Makefiles' + +As another example, the following command adds the ``file.conf`` Kconfig +fragment to the files which are merged into your final build configuration:: + + west build -- -DOVERLAY_CONFIG=file.conf + +Passing additional CMake arguments like this forces ``west build`` to re-run +CMake, even if a build system has already been generated. You can also force +a CMake re-run using the ``-c`` (or ``--cmake``) option:: + + west build -c + .. _west-flashing: Flashing: ``west flash`` @@ -41,6 +114,11 @@ To specify the build directory, use ``--build-dir`` (or ``-d``):: west flash --build-dir path/to/build/directory +Since the build directory defaults to :file:`build`, if you do not specify +a build directory but a folder named :file:`build` is present, that will be +used, allowing you to flash from outside the file:`build` folder with no +additional parameters. + Choosing a Runner ================= @@ -132,6 +210,11 @@ To specify the build directory, use ``--build-dir`` (or ``-d``):: west debug --build-dir path/to/build/directory west debugserver --build-dir path/to/build/directory +Since the build directory defaults to :file:`build`, if you do not specify +a build directory but a folder named :file:`build` is present, that will be +used, allowing you to debug from outside the file:`build` folder with no +additional parameters. + Choosing a Runner ================= diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index ef17534b..cf1340a0 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -36,7 +36,7 @@ about the tool. :maxdepth: 1 repo-tool.rst - flash-debug.rst + build-flash-debug.rst why.rst without-west.rst planned.rst From 66c6c5147b58d4b45785b959a27f2f7c6e82a3f1 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 21 Feb 2019 15:58:19 +0100 Subject: [PATCH 017/226] west: commands: build: Specify source dir without a flag In order to simplify the usage of `west build`, take a positional argument with the source directory instead of requiring the `-s, --source-dir` flag. This makes it easier and quicker to invoke west when building, as well as being consistent with CMake. Signed-off-by: Carles Cufi --- doc/guides/west/build-flash-debug.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index b3891cad..902b47d9 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -61,9 +61,9 @@ no additional parameters. whether ``-b`` is required, just try leaving it out. West will print an error if the option is required and was not given. -To specify the source directory, use ``--source-dir`` (or ``-s``):: +Specify the source directory path as the first positional argument:: - west build -b --source-dir path/to/source/directory + west build -b path/to/source/directory Additionally you can specify the build system target using the ``--target`` (or ``-t``) option. For example, to run the ``clean`` target:: @@ -79,10 +79,11 @@ Finally, you can add additional arguments to the CMake invocation performed by command. For example, to use the Unix Makefiles CMake generator instead of Ninja (which ``west build`` uses by default), run:: - west build -- -G'Unix Makefiles' + west build -b reel_board samples/hello_world -- -G'Unix Makefiles' -As another example, the following command adds the ``file.conf`` Kconfig -fragment to the files which are merged into your final build configuration:: +As another example, and assuming you have already built a sample, the following +command adds the ``file.conf`` Kconfig fragment to the files which are merged +into your final build configuration:: west build -- -DOVERLAY_CONFIG=file.conf From bd4febe9f0472b96b5c905ff3aba2c59a0fbe4f6 Mon Sep 17 00:00:00 2001 From: "David B. Kinder" Date: Fri, 8 Mar 2019 14:21:37 -0800 Subject: [PATCH 018/226] doc: use :zephyr_file: where appropriate A new role :zephyr_file: is available that renders to a link to the file or folder in GitHub. Find appropriate references using :file: and convert to :zephyr_file: to take advantage of its linking capability. Signed-off-by: David B. Kinder --- doc/guides/west/build-flash-debug.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 902b47d9..68e7ef3a 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -303,7 +303,7 @@ outside the west repository. Some reasons this choice was made are: The extension commands are a thin wrapper around a package called ``runners`` (this package is also in the Zephyr tree, in -:file:`scripts/west_commands/runners`). +:zephyr_file:`scripts/west_commands/runners`). The central abstraction within this library is ``ZephyrBinaryRunner``, an abstract class which represents *runner* objects, which can flash @@ -323,7 +323,7 @@ upstream Zephyr, the runner should be added into a new or existing .. note:: - The test cases in :file:`scripts/west_commands/tests` add unit test + The test cases in :zephyr_file:`scripts/west_commands/tests` add unit test coverage for the runners package and individual runner classes. Please try to add tests when adding new runners. Note that if your From 50629d2f169a099536c35e1db8add7bb29dbc12b Mon Sep 17 00:00:00 2001 From: Suryansh Sharma Date: Thu, 14 Mar 2019 11:01:19 +0100 Subject: [PATCH 019/226] doc: Fix typo and markup elements Fixes a typo in board_porting.rst Fixes wrong syntax for file markup element in build-flash-debug.rst Signed-off-by: Suryansh Sharma --- doc/guides/west/build-flash-debug.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 68e7ef3a..6518b3e4 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -33,7 +33,7 @@ The ``build`` command allows you to build any source tree from any directory in your file system, placing the build results in a folder of your choice. In its simplest form, the command can be run by navigating to the root folder -(i.e. the folder containing a file:`CMakeLists.txt` file) of the Zephyr +(i.e. the folder containing a :file:`CMakeLists.txt` file) of the Zephyr application of your choice and running:: west build -b @@ -49,8 +49,8 @@ To specify the build directory, use ``--build-dir`` (or ``-d``):: west build -b --build-dir path/to/build/directory Since the build directory defaults to :file:`build`, if you do not specify -a build directory but a folder named file:`build` is present, that will be used, -allowing you to incrementally build from outside the file:`build` folder with +a build directory but a folder named :file:`build` is present, that will be used, +allowing you to incrementally build from outside the :file:`build` folder with no additional parameters. .. note:: @@ -117,7 +117,7 @@ To specify the build directory, use ``--build-dir`` (or ``-d``):: Since the build directory defaults to :file:`build`, if you do not specify a build directory but a folder named :file:`build` is present, that will be -used, allowing you to flash from outside the file:`build` folder with no +used, allowing you to flash from outside the :file:`build` folder with no additional parameters. Choosing a Runner @@ -213,7 +213,7 @@ To specify the build directory, use ``--build-dir`` (or ``-d``):: Since the build directory defaults to :file:`build`, if you do not specify a build directory but a folder named :file:`build` is present, that will be -used, allowing you to debug from outside the file:`build` folder with no +used, allowing you to debug from outside the :file:`build` folder with no additional parameters. Choosing a Runner From c5ec33777486f3f2585cc62b934f4b31a083a8b1 Mon Sep 17 00:00:00 2001 From: "David B. Kinder" Date: Wed, 27 Mar 2019 08:43:42 -0700 Subject: [PATCH 020/226] doc: fix misspelling in docs and API comments Fix misspellings missed during regular reviews. Signed-off-by: David B. Kinder --- doc/guides/west/repo-tool.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index ebe0bd2c..d052b4bc 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -31,10 +31,10 @@ a multi-repo installation. When using upstream Zephyr, it looks like this: └── zephyrproject/ ├── .west/ - │   ├── config - │   └── west/ + │ ├── config + │ └── west/ ├── zephyr/ - │   └── west.yml + │ └── west.yml ├── a-project └── ... @@ -108,7 +108,7 @@ Rationale for a custom tool During the different stages of design and development for west, using already established and proven multi-repo technologies was considered multiple times. After careful analysis, no existing tool or mechanism was found suitable for -Zephyr’s use case set and requirements. The following two tools were examined +Zephyr's use case set and requirements. The following two tools were examined in detail: * Google repo @@ -277,7 +277,7 @@ installation: to the revisions present in the manifest file. West's view of multirepo history looks like this example (though some parts of -the example are specific to upstream Zephyr’s use of west): +the example are specific to upstream Zephyr's use of west): .. figure:: west-mr-model.png :align: center @@ -312,7 +312,7 @@ Notice a few important details about the above picture: - Two zephyr commits can have the same external commits (like ``F`` and ``G``). - Not all commits in some projects are associated with a zephyr commit (``P3`` "jumps" multiple commits in its history between zephyr commits ``B → C``). -- Every zephyr commit’s manifest refers to exactly one version in each of the +- Every zephyr commit's manifest refers to exactly one version in each of the other projects it cares about. The ``manifest-rev`` branch From c0b18bb4e9ca71fbfa54594bae1897aaafaccfdf Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 13 Feb 2019 15:05:47 -0700 Subject: [PATCH 021/226] doc: west: add missing parts for zephyr v1.14 - add glossary terms for important concepts we have to explain often, like "west installation" - add autodoc directives for pulling in west API docs - add missing documentation for built-in features like west's configuration, extension commands, etc. - add missing documentation for "west sign" extension - describe the manifest in a self-contained way rather than linking to the relevant pykwalify schema, also adding a missing reference to "west manifest" in the miscellaneous multi-repo commands list - move various details regarding history and motivation to why.rst among other changes to repo-tool.rst, leaving it closer to a "tell me what I really need to know" style overview - update planned features Fixes: #14992 Signed-off-by: Marti Bolivar --- doc/guides/west/config.rst | 152 ++++++++ doc/guides/west/extensions.rst | 244 +++++++++++++ doc/guides/west/index.rst | 54 +-- doc/guides/west/manifest.rst | 284 +++++++++++++++ doc/guides/west/planned.rst | 23 +- doc/guides/west/repo-tool.rst | 555 ++++++++++------------------- doc/guides/west/sign.rst | 55 +++ doc/guides/west/west-apis.rst | 89 ++++- doc/guides/west/west-not-found.rst | 7 + doc/guides/west/why.rst | 119 ++++++- 10 files changed, 1169 insertions(+), 413 deletions(-) create mode 100644 doc/guides/west/config.rst create mode 100644 doc/guides/west/extensions.rst create mode 100644 doc/guides/west/manifest.rst create mode 100644 doc/guides/west/sign.rst diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst new file mode 100644 index 00000000..6f7bb389 --- /dev/null +++ b/doc/guides/west/config.rst @@ -0,0 +1,152 @@ +.. _west-config: + +Configuration +############# + +This page documents west's configuration file system, the ``west config`` +command, and configuration options used by built-in commands. For API +documentation on the ``west.configuration`` module, see +:ref:`west-apis-configuration`. + +West Configuration Files +------------------------ + +West's configuration file syntax is INI-like; here is an example file: + +.. code-block:: ini + + [manifest] + path = zephyr + + [zephyr] + base = zephyr + +Above, the ``manifest`` section has option ``path`` set to ``zephyr``. Another +way to say the same thing is that ``manifest.path`` is ``zephyr`` in this file. + +There are three types of configuration file: + +1. **System**: Settings in this file affect west's behavior for every user + logged in to the computer. Its location depends on the platform: + + - Linux: :file:`/etc/westconfig` + - macOS: :file:`/usr/local/etc/westconfig` + - Windows: :file:`%PROGRAMDATA%\\west\\config` + +2. **Global** (per user): Settings in this file affect how west behaves when + run by a particular user on the computer. + + - All platforms: the default is :file:`.westconfig` in the user's home + directory. + - Linux note: if the environment variable :envvar:`XDG_CONFIG_HOME` is set, + then :file:`$XDG_CONFIG_HOME/west/config` is used. + - Windows note: the following environment variables are tested to find the + home directory: :envvar:`%HOME%`, then :envvar:`%USERPROFILE%`, then a + combination of :envvar:`%HOMEDRIVE%` and :envvar:`%HOMEPATH%`. + +3. **Local**: Settings in this file affect west's behavior for the + current :term:`west installation`. The file is :file:`.west/config`, relative + to the installation's root directory. + +A setting in a file which appears lower down on this list overrides an earlier +setting. For example, if ``color.ui`` is ``true`` in the system's configuration +file, but ``false`` in the installation's, then the final value is +``false``. Similarly, settings in the user configuration file override system +settings, and so on. + +.. _west-config-cmd: + +West ``config`` Command +----------------------- + +The built-in ``config`` command can be used to get and set configuration +values. You can pass ``west config`` the options ``--system``, ``--global``, or +``--local`` to specify which configuration file to use. Only one of these can +be used at a time. If none is given, then writes default to ``--local``, and +reads show the final value after applying overrides. + +Some examples for common uses follow; run ``west config -h`` for detailed help, +and see :ref:`west-config-index` for more details on built-in options. + +To set ``manifest.path`` to :file:`some-other-manifest`: + +.. code-block:: console + + west config manifest.path some-other-manifest + +Doing the above means that commands like ``west update`` will look for the +:term:`west manifest` inside the :file:`some-other-manifest` directory +(relative to the installation root directory) instead of the directory given to +``west init``, so be careful! + +To read ``zephyr.base``, the value which will be used as ``ZEPHYR_BASE`` if it +is unset in the calling environment (also relative to the installation root): + +.. code-block:: console + + west config zephyr.base + +You can switch to another zephyr repository without changing ``manifest.path`` +-- and thus the behavior of commands like ``west update`` -- using: + +.. code-block:: console + + west config zephyr.base some-other-zephyr + +This can be useful if you use commands like ``git worktree`` to create your own +zephyr directories, and want commands like ``west build`` to use them instead +of the zephyr repository specified in the manifest. (You can go back to using +the directory in the upstream manifest by running ``west config zephyr.base +zephyr``.) + +To set ``color.ui`` to ``false`` in the global (user-wide) configuration file, +so that west will no longer print colored output for that user when run in any +installation: + +.. code-block:: console + + west config --global color.ui false + +To undo the above change: + +.. code-block:: console + + west config --global color.ui true + +.. _west-config-index: + +Built-in Configuration Options +------------------------------ + +The following table documents configuration options supported by west's built-in +commands. + +.. NOTE: docs authors: keep this table sorted by section, then option. + +.. list-table:: + :widths: 10 30 + :header-rows: 1 + + * - Option + - Description + * - ``color.ui`` + - Boolean. If ``true`` (the default), then west output is colorized when + stdout is a terminal. + * - ``commands.allow_extensions`` + - Boolean, default ``true``, disables :ref:`west-extensions` if ``false`` + * - ``manifest.path`` + - String, relative path from the :term:`west installation` root directory + to the manifest repository used by ``west update`` and other commands + which parse the manifest. Set locally by ``west init``. + * - ``zephyr.base`` + - String, default value to set for the :envvar:`ZEPHYR_BASE` environment + variable while the west command is running. By default, this is set to + the path to the manifest project with path :file:`zephyr` (if there is + one) during ``west init``. If the variable is already set, then this + setting is ignored unless ``zephyr.base-prefer`` is ``"configfile"``. + * - ``zephyr.base-prefer`` + - String, one the values ``"env"`` and ``"configfile"``. If set to + ``"env"`` (the default), setting :envvar:`ZEPHYR_BASE` in the calling + environment overrides the value of the ``zephyr.base`` configuration + option. If set to ``"configfile"``, the configuration option wins + instead. diff --git a/doc/guides/west/extensions.rst b/doc/guides/west/extensions.rst new file mode 100644 index 00000000..f770c664 --- /dev/null +++ b/doc/guides/west/extensions.rst @@ -0,0 +1,244 @@ +.. _west-extensions: + +Extensions +########## + +West is "pluggable": you can add your own commands to west without editing its +source code. These are called **west extension commands**, or just "extensions" +for short. Extensions show up in the ``west --help`` output in a special +section for the project which defines them. This page provides general +information on west extension commands, and has a tutorial for writing your +own. + +Some commands you can run when using west with Zephyr, like the ones used to +:ref:`build, flash, and debug `, are extensions. That's +why help for them shows up like this in ``west --help``: + +.. code-block:: none + + commands from project at "zephyr": + build: compile a Zephyr application + sign: sign a Zephyr binary for bootloader chain-loading + flash: flash and run a binary on a board + debug: flash and interactively debug a Zephyr application + debugserver: connect to board and launch a debug server + attach: interactively debug a board + +See :file:`zephyr/scripts/west-commands.yml` and the +:file:`zephyr/scripts/west_commands` directory for the implementation details. + +Disabling Extension Commands +**************************** + +To disable support for extension commands, set the ``commands.allow_extensions`` +:ref:`configuration ` option to ``false``. To set this +globally for whenever you run west, use: + +.. code-block:: console + + west config --global commands.allow_extensions false + +If you want to, you can then re-enable them in a particular installation with: + +.. code-block:: console + + west config --local commands.allow_extensions true + +Note that the files containing extension commands are not imported by west +unless the commands are explicitly run. See below for details. + +Adding a West Extension +*********************** + +There are three steps to adding your own extension: + +#. Write the code implementing the command. +#. Add information about it to a :file:`west-commands.yml` file. +#. Make sure the :file:`west-commands.yml` file is referenced in the + :term:`west manifest`. + +Note that west ignores extension commands whose names are the same as a +built-in command. + +Step 1: Implement Your Command +============================== + +Create a Python file to contain your command implementation (see the "Meta > +Requires" information on the `west PyPI page`_ for details on the currently +supported versions of Python). You can put it in anywhere in any project +tracked by your :term:`west manifest`, or the manifest repository itself. +This file must contain a subclass of the ``west.commands.WestCommand`` class; +this class will be instantiated and used when your extension is run. + +Here is a basic skeleton you can use to get started. It contains a subclass of +``WestCommand``, with implementations for all the abstract methods. For more +details on the west APIs you can use, see :ref:`west-apis`. + +.. code-block:: py + + '''my_west_extension.py + + Basic example of a west extension.''' + + from textwrap import dedent # just for nicer code indentation + + from west.commands import WestCommand # your extension must subclass this + from west import log # use this for user output + + class MyCommand(WestCommand): + + def __init__(self): + super().__init__( + 'my-command-name', # gets stored as self.name + 'one-line help for what my-command-name does', # self.help + # self.description: + dedent(''' + A multi-line description of my-command. + + You can split this up into multiple paragraphs and they'll get + reflowed for you. You can also pass + formatter_class=argparse.RawDescriptionHelpFormatter when calling + parser_adder.add_parser() below if you want to keep your line + endings.''')) + + def do_add_parser(self, parser_adder): + # This is a bit of boilerplate, which allows you full control over the + # type of argparse handling you want. The "parser_adder" argument is + # the return value of an argparse.ArgumentParser.add_subparsers() call. + parser = parser_adder.add_parser(self.name, + help=self.help, + description=self.description) + + # Add some example options using the standard argparse module API. + parser.add_argument('-o', '--optional', help='an optional argument') + parser.add_argument('required', help='a required argument') + + return parser # gets stored as self.parser + + def do_run(self, args, unknown_args): + # This gets called when the user runs the command, e.g.: + # + # $ west my-command-name -o FOO BAR + # --optional is FOO + # required is BAR + log.inf('--optional is', args.optional) + log.inf('required is', args.required) + +You can ignore the second argument to ``do_run()`` (``unknown_args`` above), as +``WestCommand`` will reject unknown arguments by default. If you want to be +passed a list of unknown arguments instead, add ``accepts_unknown_args=True`` +to the ``super().__init__()`` arguments. + +Step 2: Add or Update Your :file:`west-commands.yml` +==================================================== + +You now need to add a :file:`west-commands.yml` file to your project which +describes your extension to west. + +Here is an example for the above class definition, assuming it's in +:file:`my_west_extension.py` at the project root directory: + +.. code-block:: yaml + + west-commands: + - file: my_west_extension.py + commands: + - name: my-command-name + class: MyCommand + help: one-line help for what my-command-name does + +The top level of this YAML file is a map with a ``west-commands`` key. The +key's value is a sequence of "command descriptors". Each command descriptor +gives the location of a file implementing west extensions, along with the names +of those extensions, and optionally the names of the classes which define them +(if not given, the ``class`` value defaults to the same thing as ``name``). + +Some information in this file is redundant with definitions in the Python code. +This is because west won't import :file:`my_west_extension.py` until the user +runs ``west my-command-name``, since: + +- It allows users to run ``west update`` with a manifest from an untrusted + source, then use other west commands without your code being imported along + the way. Since importing a Python module is shell-equivalent, this provides + some peace of mind. + +- It's a small optimization, since your code will only be imported if it is + needed. + +So, unless your command is explicitly run, west will just load the +:file:`west-commands.yml` file to get the basic information it needs to display +information about your extension to the user in ``west --help`` output, etc. + +If you have multiple extensions, or want to split your extensions across +multiple files, your :file:`west-commands.yml` will look something like this: + +.. code-block:: yaml + + west-commands: + - file: my_west_extension.py + commands: + - name: my-command-name + class: MyCommand + help: one-line help for what my-command-name does + - file: another_file.py + commands: + - name: command2 + help: another cool west extension + - name: a-third-command + class: ThirdCommand + help: a third command in the same file as command2 + +Above: + +- :file:`my_west_extension.py` defines extension ``my-command-name`` + with class ``MyCommand`` +- :file:`another_file.py` defines two extensions: + + #. ``command2`` with class ``command2`` + #. ``a-third-command`` with class ``ThirdCommand`` + +See the file :file:`west-commands-schema.yml` in the `west repository`_ for a +schema describing the contents of a :file:`west-comands.yml`. + +Step 3: Update Your Manifest +============================ + +Finally, you need to specify the location of the :file:`west-commands.yml` you +just edited in your west manifest. If your extension is in a project, add it +like this: + +.. code-block:: yaml + + manifest: + # [... other contents ...] + + projects: + - name: your-project + west-commands: path/to/west-commands.yml + # [... other projects ...] + +Where :file:`path/to/west-commands.yml` is relative to the root of the project. +Note that the name :file:`west-commands.yml`, while encouraged, is just a +convention; you can name the file something else if you need to. + +Alternatively, if your extension is in the manifest repository, just do the +same thing in the manifest's ``self`` section, like this: + +.. code-block:: yaml + + manifest: + # [... other contents ...] + + self: + west-commands: path/to/west-commands.yml + +That's it; you can now run ``west my-command-name``. Your command's name, help, +and the project which contains its code will now also show up in the ``west +--help`` output. If you share the updated repositories with others, they'll be +able to use it, too. + +.. _west PyPI page: + https://pypi.org/project/west/ + +.. _west repository: + https://github.com/zephyrproject-rtos/west/ diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index cf1340a0..4204aaa3 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -3,40 +3,36 @@ West (Zephyr's meta-tool) ######################### -The Zephyr project includes a swiss-army knife command line tool -named ``west`` (Zephyr is an English name for the Latin -`Zephyrus `_, the ancient Greek god -of the west wind). +The Zephyr project includes a swiss-army knife command line tool named +``west``\ [#west-name]_. West is developed in its own `repository`_. Like +``git`` and ``docker``, the top-level ``west`` command takes some common +options, a sub-command to run, and then options and arguments for that +sub-command:: -West is used upstream to obtain the source code for the Zephyr project and can -also be used to build, debug, and flash applications. It is developed in its -own `repository on GitHub`_. The source code retrieval features include a -multiple repository management system with features inspired by Google's Repo -tool and Git submodules. + west [common-opts] [opts] -West is also pluggable: you can write your own west "extension commands" to add -additional features. Extension commands can be in any directory in your -installation; they don't have to be defined in the zephyr or west repositories. +West's built-in commands provide a multiple repository management system with +features inspired by Google's Repo tool and Git submodules. West is also +pluggable: you can write your own west "extension commands" which add +additional features to west. Zephyr provides extension commands for building +applications, debugging them, and more. -Like :program:`git` and :program:`docker`, the top-level :program:`west` -command takes some options, a sub-command to run, and then options specific to -that sub-command:: +You can run ``west --help`` (or ``west -h`` for short) to get top-level help +for available west commands, and ``west -h`` for detailed help on +each command. - west [common-opts] [command-opts] [] - -After you've :ref:`created a Zephyr installation using west `, -you can run ``west --help`` (or ``west -h`` for short) to get top-level help on -west's built-in commands along with any extension commands available in your -installation. - -The following pages describe how to use west, and provide additional context -about the tool. +The following pages document west's ``v0.5.x`` releases, and provide additional +context about the tool. .. toctree:: :maxdepth: 1 repo-tool.rst + manifest.rst + config.rst + extensions.rst build-flash-debug.rst + sign.rst why.rst without-west.rst planned.rst @@ -44,5 +40,13 @@ about the tool. For details on west's Python APIs (including APIs provided by extensions in the zephyr), see :ref:`west-apis`. -.. _repository on GitHub: +.. rubric:: Footnotes + +.. [#west-name] + + Zephyr is an English name for the Latin `Zephyrus + `_, the ancient Greek god of the + west wind. + +.. _repository: https://github.com/zephyrproject-rtos/west diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst new file mode 100644 index 00000000..5a4b14ea --- /dev/null +++ b/doc/guides/west/manifest.rst @@ -0,0 +1,284 @@ +.. _west-manifests: + +West Manifests +############## + +This page contains detailed information about west's multiple repository model +and manifest files. For API documentation on the ``west.manifest`` module, see +:ref:`west-apis-manifest`. For a more general introduction and command +overview, see :ref:`west-multi-repo`. + +.. _west-mr-model: + +Multiple Repository Model +************************* + +West's view of the repositories in a :term:`west installation`, and their +history, looks like the following figure (though some parts of this example are +specific to upstream Zephyr's use of west): + +.. figure:: west-mr-model.png + :align: center + :alt: West multi-repo history + :figclass: align-center + + West multi-repo history + +The history of the manifest repository is the line of Git commits which is +"floating" on top of the gray plane. Parent commits point to child commits +using solid arrows. The plane below contains the Git commit history of the +repositories in the installation, with each project repository boxed in by a +rectangle. Parent/child commit relationships in each repository are also shown +with solid arrows. + +The commits in the manifest repository (again, for upstream Zephyr this is the +zephyr repository itself) each have a manifest file. The manifest file in each +commit specifies the corresponding commits which it expects in each of the +project repositories. This relationship is shown using dotted line arrows in the +diagram. Each dotted line arrow points from a commit in the manifest repository +to a corresponding commit in a project repository. + +Notice the following important details: + +- Projects can be added (like ``P1`` between manifest repository + commits ``D`` and ``E``) and removed (``P2`` between the same + manifest repository commits) + +- Project and manifest repository histories don't have to move + forwards or backwards together: + + - ``P2`` stays the same from ``A → B``, as do ``P1`` and ``P3`` from ``F → + G``. + - ``P3`` moves forward from ``A → B``. + - ``P3`` moves backward from ``C → D``. + + One use for moving backward in project history is to "revert" a regression by + going back to a revision before it was introduced. + +- Project repository commits can be "skipped": ``P3`` moves forward + multiple commits in its history from ``B → C``. + +- In the above diagram, no project repository has two revisions "at + the same time": every manifest file refers to exactly one commit in + the projects it cares about. This can be relaxed by using a branch + name as a manifest revision, at the cost of being able to bisect + manifest repository history. + +Manifest Files +************** + +A west manifest is a YAML file named :file:`west.yml`. Manifests have two +top-level "sections", ``west`` and ``manifest``, like this: + +.. code-block:: yaml + + west: + # contents of west section + manifest: + # contents of manifest section + +In YAML terms, the manifest file contains a mapping, with two keys relevant to +west at top level. These keys are the scalar strings ``west`` and +``manifest``. Their contents are described next. + +West Section +============ + +.. note:: + + Support for this feature will be removed in a future version of west, when + the west repository is no longer cloned into the installation. + +The ``west`` section specifies the URL and revision of the west repository +which is cloned into the installation. For example: + +.. code-block:: yaml + + west: + url: https://example.com/west + revision: v0.5.6 + +This specifies cloning the west repository from URL +``https://example.com/west`` (any URL accepted by ``git clone`` will work), at +revision ``v0.5.6``. The revision can be a Git branch, tag, or SHA. + +That is, the west section also contains a mapping, with permitted keys ``url`` +and ``revision``. These specify the fetch URL and Git revision for the west +repository to clone into the installation, as described in +:ref:`west-struct`. If not given, the default URL is +https://github.com/zephyrproject-rtos/west, and the default revision is +``master``. + +The file :file:`west-schema.yml` in the west source code repository contains a +pykwalify schema for this section's contents. + +Manifest Section +================ + +This is the main section in the manifest file. There are four subsections: +``defaults``, ``remotes``, ``projects``, and ``self``. In YAML terms, the value +of the ``manifest`` key is also a mapping, with these "subsections" as keys. +For example: + +.. code-block:: yaml + + manifest: + defaults: + # contents of defaults subsection + remotes: + # contents of remotes subsection + projects: + # contents of projects subsection + self: + # contents of self subsection + +The ``remotes`` and ``projects`` subsections are the only mandatory ones, so +we'll cover them first. + +The ``remotes`` subsection contains a sequence which specifies the base URLs +where projects can be fetched from. Each sequence element has a name and a "URL +base". These are used to form the complete fetch URL for each project. For +example: + +.. code-block:: yaml + + manifest: + # [...] + remotes: + - name: remote1 + url-base: https://example.com/base1 + - name: remote2 + url-base: https://example.com/base2 + +Above, two remotes are given, with names ``remote1`` and ``remote2``. Their URL +bases are respectively ``https://example.com/base1`` and +``https://example.com/base2``. You can use SSH URL bases as well; for example, +you might use ``git@example.com:base1`` if ``remote1`` supported Git over SSH +as well. Anything acceptable to Git will work. + +The ``projects`` subsection contains a sequence describing the +project repositories in the west installation. Each project has a +name and a remote; the project's name is appended to the remote URL +base to form the Git fetch URL west uses to clone the project and keep +it up to date. Here is a simple example; we'll assume the ``remotes`` +given above. + +.. code-block:: yaml + + manifest: + # [...] + projects: + - name: proj1 + remote: remote1 + path: extra/project-1 + - name: proj2 + remote: remote1 + revision: v1.3 + - name: proj3 + remote: remote2 + revision: abcde413a111 + +This example has three projects: + +- ``proj1`` has remote ``remote1``, so its Git fetch URL is + ``https://example.com/base1/proj1`` (note that west adds the ``/`` between + the URL base and project name). This project will be cloned at path + ``extra/project-1`` relative to the west installation's root directory. + Since the project has no ``revision``, the current tip of the ``master`` + branch will be checked out as a detached ``HEAD``. + +- ``proj2`` has the same remote, so its fetch URL is + ``https://example.com/base1/proj2``. Since the project has no ``path`` + specified, it will be cloned at ``proj2`` (i.e. a project's ``name`` is used + as its default ``path``). The commit pointed to by the ``v1.3`` tag will be + checked out. + +- ``proj3`` has fetch URL ``https://example.com/base2/proj3`` and will be + cloned at path ``proj3``. Commit ``abcde413a111`` will be checked out. + +Each element in the ``projects`` sequence can contain the following keys. Some +of the description refers to the ``defaults`` subsection, which will be +described next. + +- ``name``: Mandatory, the name of the project. The fetch URL is formed as + remote url-base + '/' + ``name``. The name cannot be one of the reserved + values "west" and "manifest". +- ``remote``: The name of the project's remote. If not given, the ``remote`` + value in the ``defaults`` subsection is tried next. If both are missing, the + manifest is invalid. +- ``revision``: Optional. The current project revision used by ``west update``. + If not given, the value from the ``defaults`` subsection will be used if + present. If both are missing, ``master`` is used. A project revision can be + a branch, tag, or SHA. The names of unqualified branch and tag revisions are + fetched as-is. For qualified refs, like ``refs/heads/foo``, the last + component (``foo``) is used. +- ``path``: Optional. Where to clone the repository locally. If missing, it's + cloned in the west installation's root subdirectory given by the project's + name. +- ``clone-depth``: Optional. If given, a positive integer which creates a + shallow history in the cloned repository limited to the given number of + commits. +- ``west-commands``: Optional. If given, a relative path to a YAML file within + the project which describes additional west commands provided by that + project. This file is named :file:`west-commands.yml` by convention. See + :ref:`west-extensions` for details. + +The ``defaults`` subsection can provide default values for project-related +values. In particular, the default remote name and revision can be specified +here. Another way to write the same manifest we have been describing so far +using ``defaults`` is: + +.. code-block:: yaml + + manifest: + defaults: + remote: remote1 + revision: v1.3 + + remotes: + - name: remote1 + url-base: https://example.com/base1 + - name: remote2 + url-base: https://example.com/base2 + + projects: + - name: proj1 + path: extra/project-1 + revision: master + - name: proj2 + - name: proj3 + remote: remote2 + revision: abcde413a111 + +Finally, the ``self`` subsection can be used to control the behavior of the +manifest repository itself. Its value is a map with the following keys: + +- ``path``: Optional. The path to clone the manifest repository into, relative + to the west installation's root directory. If not given, the basename of the + path component in the manifest repository URL will be used by default. For + example, if the URL is ``https://example.com/project-repo``, the manifest + repository would be cloned to the directory :file:`project-repo`. + +- ``west-commands``: Optional. This is analogous to the same key in a + project sequence element. + +As an example, let's consider this snippet from the zephyr repository's +:file:`west.yml`: + +.. code-block:: yaml + + manifest: + # [...] + self: + path: zephyr + west-commands: scripts/west-commands.yml + +This ensures that the zephyr repository is cloned into path ``zephyr``, though +as explained above that would have happened anyway if cloning from the default +manifest URL, ``https://github.com/zephyrproject-rtos/zephyr``. Since the +zephyr repository does contain extension commands, its ``self`` entry declares +the location of the corresponding :file:`west-commands.yml` relative to the +repository root. + +The pykwalify schema :file:`manifest-schema.yml` in the west source code +repository is used to validate the manifest section. diff --git a/doc/guides/west/planned.rst b/doc/guides/west/planned.rst index 3b4d5658..81582645 100644 --- a/doc/guides/west/planned.rst +++ b/doc/guides/west/planned.rst @@ -2,18 +2,21 @@ Planned Features ================ Additional west features are under development for future versions of -Zephyr: +Zephyr. These include: -- Running Zephyr in emulation. +- Multiple manifest files: support for having multiple files which have + manifest data, instead of the single :file:`west.yml` supported today. + See `west #221`_. -- Bootloader integration: bootloader-aware image building, signing, - and flashing, as well as building and flashing the bootloader itself. +- Toolchain awareness: see `west #180`_. -- Additional multiple repository support: fetching and updating repositories - that integrate with Zephyr, such as `MCUboot`_, `OpenThread`_ and others. +See the `west repository issues`_ page for more. -.. _MCUboot: - https://mcuboot.com/ +.. _west #221: + https://github.com/zephyrproject-rtos/west/issues/221 -.. _OpenThread: - https://openthread.io/ +.. _west #180: + https://github.com/zephyrproject-rtos/west/issues/180 + +.. _west repository issues: + https://github.com/zephyrproject-rtos/west/issues diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index d052b4bc..c85fbf90 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -3,445 +3,258 @@ Multiple Repository Management ############################## -Introduction -************ - -West includes a set of commands for working with projects composed of multiple -Git repositories installed under a common parent directory (a *west -installation*), similar to how `Git Submodules -`_ and Google's `repo -`_ work. - -The rest of this page introduces these multi-repo concepts and gives an -overview of the associated west commands, along with an example workflow. See -`Zephyr issue #6770`_ for additional background and discussion. +This page introduces basic concepts related to West and its multiple repository +management features, and gives an overview of the associated commands. See +:ref:`west-history` and `Zephyr issue #6770`_ for additional discussion, +rationale, and motivation. .. note:: - The multi-repo commands are meant to augment Git in minor ways for - multi-repo work, not replace it. For tasks that aren't multi-repo-related, - use plain Git commands. - This page explains what the west multi-repo commands do behind the scenes. - -A west installation is the result of running the ``west init`` command to -either create a new installation or convert a standalone zephyr repository into -a multi-repo installation. When using upstream Zephyr, it looks like this: - -.. code-block:: console - - └── zephyrproject/ - ├── .west/ - │ ├── config - │ └── west/ - ├── zephyr/ - │ └── west.yml - ├── a-project - └── ... - -Above, :file:`zephyrproject` is the name of the west installation's common -parent directory, and :file:`a-project` is another project managed by west in -the installation. The file :file:`.west/config` is the installation's west -configuration file. The directory :file:`.west/west` is a clone of the west -repository itself; more details on why that is needed are given below. - -Every west installation contains a *manifest repository*, which is a Git -repository containing a file named :file:`west.yml`. This file, along with -what's in :file:`.west`, controls the installation's behavior. In the above -example, zephyr is the manifest repository. However, as you'll see below, any -repository in an installation can be the manifest repository; it doesn't have -to be zephyr. However, every installation has exactly one manifest repository; -its location is specified in :file:`.west/config`. Alongside the manifest -repository are *projects*, which are Git repositories specified by -:file:`west.yml`. - -Requirements -************ - -Although the motivation behind splitting the Zephyr codebase into multiple -repositories is outside of the scope of this page, the fundamental requirements -along with a clear justification of the choice not to use existing tools and -instead develop a new one, do belong here. -At the most fundamental level, the requirements for a transition to multiple -repositories in the Zephyr Project are: - -* **R1**: Keep externally maintained code outside of the main repository -* **R2**: Provide a tool that both Zephyr users and distributors can make use of - to benefit from and extend the functionality above -* **R3**: Allow overriding or removing repositories without having to make changes - to the zephyr repository -* **R4**: Support both continuous tracking and commit-based (bisectable) project - updating - -Topologies supported -******************** + West's multi-repo commands are meant to augment Git in minor ways for + multi-repo work, not to replace it. For tasks that only operate on one + repository, just use plain Git commands. -The requirements above lead us to the three main source code organization -topologies that we intend to address with west: - -* **T1**: Star topology with zephyr as the manifest repository: - - - The zephyr repository acts as the central repository and includes a - complete list of projects in itself - - Default (upstream) configuration - - Analogy with existing mechanisms: Git submodules with zephyr as the - superproject - -* **T2**: Star topology with an application repository as the manifest repository - - - The application repository acts as the central repository and includes a - complete list of projects in itself - - Useful for downstream distributions focused in a single application - repository - - Analogy with existing mechanisms: Git submodules with the application as - the superproject, zephyr as a submodule - -* **T3**: Forest topology with a set of trees all at the same level - - - A dedicated manifest repository contains only a list of repositories - - Useful for downstream distributions that track the latest ``HEAD`` on all - repositories - - Analogy with existing mechanisms: Google repo-based distribution - -Rationale for a custom tool -*************************** +.. _west-installation: -During the different stages of design and development for west, using already -established and proven multi-repo technologies was considered multiple times. -After careful analysis, no existing tool or mechanism was found suitable for -Zephyr's use case set and requirements. The following two tools were examined -in detail: - -* Google repo - - - The tool is Python 2 only - - Does not play well with Windows - - It is poorly documented and maintained - - It does not fully support a set of bisectable repositories without - additional intervention (**R4**) - -* Git submodules - - - Does not fully support **R1**, since the externally maintained repositories - would still need to be inside the main zephyr Git tree - - Does not support **R3**. Downstream copies would need to either delete or - replace submodule definitions - - Does not support continuous tracking of the latest ``HEAD`` in external - repositories (**R4**) - - Requires hardcoding of the paths/locations of the external repositories - -Finally, please see :ref:`west-history` for the motivations behind using a -single tool for both multi-repository management as well as building, debugging -and flashing. +Introduction +************ +West's built-in commands allow you to work with projects composed of multiple +Git repositories installed under a common parent directory, which we call a +*west installation*. This works similarly to `Git Submodules +`_ and Google's `repo +`_. + +A west installation is the result of running the ``west init`` command, which +is described in more detail below. This command can either create a new +installation, or convert a standalone "mono-repo" zephyr repository into a full +west installation. For upstream Zephyr, the installation looks like this: + +.. code-block:: none + + zephyrproject + ├── .west + │ ├── config + │ └── west + ├── zephyr + │ ├── west.yml + │ └── [... other files ...] + ├── modules + │ └── lib + │ └── tinycbor + ├── net-tools + └── [ ... other projects ...] + +Above, :file:`zephyrproject` is the name of the west installation's root +directory. This name is just an example -- it could be anything, like ``z``, +``my-zephyr-installation``, etc. The file :file:`.west/config` is the +installation's :ref:`local configuration file `. The directory +:file:`.west/west` is a clone of the west repository itself; more details on +why that is currently needed are given in the next section. + +Every west installation contains exactly one *manifest repository*, which is a +Git repository containing a file named :file:`west.yml`, which is the *west +manifest*. The location of the manifest repository is given by the +:ref:`manifest.path configuration option ` in the local +configuration file. The manifest file, along with west's configuration files, +controls the installation's behavior. For upstream Zephyr, :file:`zephyr` is +the manifest repository, but you can configure west to use any Git repository +in the installation as the manifest repository. The only requirement is that it +contains a valid manifest file. See :ref:`west-manifests` for more details on +what this means. + +Both of the :file:`tinycbor` and :file:`net-tools` directories are *projects* +managed by west, and configured in the manifest file. A west installation can +contain arbitrarily many projects. As shown above, projects can be located +anywhere in the installation. They don't have to be subdirectories of the +manifest directory, and they can be inside of arbitrary subdirectories inside +the installation's root directory. By default, the Zephyr build system uses +west to get the locations of all the projects in the installation, so any code +they contain can be used by applications. This behavior can be overridden using +the ``ZEPHYR_MODULES`` CMake variable; see +:zephyr_file:`cmake/zephyr_module.cmake` for details. + +Finally, any repository managed by a west installation can contain +:ref:`extension commands `, which are extra west commands +provided by that project. This includes the manifest repository and any project +repository. .. _west-struct: -Structure -********* +West Structure +************** -West structure -============== +West is currently split in two: -West is currently downloaded and installed on a system in the following stages: - -* Bootstrapper: Installed using ``pip``, implements ``west init`` -* Installation: Installed using ``west init``, implements built-in multi-repo - commands -* Extension commands: Installed using ``west update``, parses the manifest - in the west installation for additional commands +* Bootstrapper: Installed by ``pip3 install west``, which provides the ``west`` + binary and the ``west init`` command. +* Per-installation clone: this is the west repository cloned into each + installation, which provides the built-in commands. .. note:: - The separation between the "bootstrapper" and "installation" pieces is - inspired by the Google Repo tool, but it's a temporary structure for - convenience. In the future, the two will be merged. This will lessen the - complexity of the design and make it easier to write and debug extension - commands. - -Repository structure -==================== + This "bootstrapper" / "everything else" separation is similar to the model + used by Google's ``repo`` tool, but unfortunately in retrospect was not a + good strategy for west. -Beyond west itself, the actual code repositories that west works with -are the following: + In future versions, the ``west`` binary and all built-in commands (including + ``init``) will be installed by ``pip3 install west``. Besides eliminating + complexity, this will also make it possible to use :ref:`West's APIs + ` from any Python file, not just extension + commands. -* Manifest repository: Cloned by ``west init``, and managed afterward with Git - by the user. Contains the list of projects in the manifest file - :file:`west.yml`. In the case of upstream Zephyr, the zephyr repository is - the manifest repository. -* Projects: Cloned and managed by ``west update``. Listed in the manifest file. + Updating west will still be possible manually, e.g. with ``pip3 + install --upgrade west``. If necessary, it will also still be possible to + use different versions of west on the same computer through Python virtual + environments. Bootstrapper ============ The bootstrapper module is distributed using `PyPI`_ and installed using -:file:`pip`. A launcher named ``west`` is placed by :file:`pip` in the user's +:file:`pip3`. A launcher named ``west`` is placed by :file:`pip3` in the user's ``PATH``. This the only entry point to west. It implements a single command: ``west init``. This command needs to be run first to use the rest of functionality included in ``west``, by creating a west installation. The command ``west init`` does the following: -* Clone west itself in a :file:`.west/west` folder in the installation -* Clone the manifest repository in the folder specified by the manifest file's - (:file:`west.yml`) ``self.path`` section. Additional information - on the manifest can be found in the :ref:`west-multi-repo` section) +* Clones west itself in a :file:`.west/west` folder in the installation. +* Clones the manifest repository in the folder specified by the manifest file's + ``self.path`` section. +* Creates an initial local configuration file. Once ``west init`` has been run, the bootstrapper will delegate the handling of -any west commands other than ``init`` to the cloned west installation. - -This means that there is a single bootstrapper instance installed at any time -(unless you use virtual environments), which can then be used to initialize as -many installations as needed. +any west commands other than ``init`` to the cloned west repository. This means +that there is a single bootstrapper instance installed at any time (unless you +use virtual environments), which can then be used to initialize as many +installations as needed, each of which can have a different version of west. .. _west-struct-installation: -Installation -============ - -A west installation, as describe above, contains a clone of the west repository -in :file:`.west/west`. The clone of west in the installation is where the -built-in multi-repo command implementations are currently provided. - -When running a west command, the bootstrapper delegates handling for all -commands except ``init`` to the :file:`.west/west` repository in the current -installation. +Per-Installation Clone +====================== -Extension Commands -================== - -The west manifest file (more about which below) allows any repository in the -installation to provide additional west commands (the flash and debug commands -use this mechanism; they are defined in the west repository). Every repository -which includes extension commands must provide a YAML file which configures the -names of the commands, the Python files that implement them, and other -metadata. - -The locations of these YAML files throughout the installation are specified in -the manifest, which you'll read about next. - -.. _west-mr-model: - -Model -***** - -Manifest -======== - -A **manifest** is a `YAML `_ file that, at a minimum, gives the -URL and revision for each project repository in the multi-repo (each **project**). -The manifest is stored in the **manifest repository** and is named :file:`west.yml`. - -The format of the west manifest is described by a pykwalify schema, `manifest-schema.yml -`_. - -A west-based Zephyr installation has a special manifest repository. This -repository contains the west manifest file named :file:`west.yml`. The west -manifest contains: - -* A list of the projects (Git repositories) in the installation and - metadata about them (where to clone them from, what revision to check out, - etc.). Externally maintained projects (vendor HALs, crypto libraries, etc) - will be moved into their own repositories as part of the transition to - multi-repository, and will be managed using this list. - -* Metadata about the manifest repository, such as what path to clone it into in - the Zephyr installation. - -* Optionally, a description of how to clone west itself (this allows users to - fork west itself, should that be necessary). - -* Additionally both the projects and the metadata about the manifest repository - can optionally include information about additional west commands (extensions) - that are contained inside the Git repositories. - -Repositories -============ - -There are therefore three types of repositories that exist in a west-based Zephyr -installation: - -* West repository: This is cloned by ``west init`` and placed in - :file:`.west/west` - -* Manifest repository: This is the repository that contains the :file:`west.yml` - manifest file described above which lists all the projects. The manifest - repository can either contain only the manifest itself or also have actual - code in it. In the case of the upstream Zephyr Project, the manifest - repository is the `zephyr repository `_, - which contains all zephyr source code except for externally maintained - projects, which are listed in the :file:`west.yml` manifest file. - It is the user's responsibility to update this repository using Git. - -* Project repositories: In the context of west, projects are source code - repositories that are listed in the manifest file, :file:`west.yml` contained - inside the manifest repository. West manages projects, updating them according - to the revisions present in the manifest file. - -West's view of multirepo history looks like this example (though some parts of -the example are specific to upstream Zephyr's use of west): - -.. figure:: west-mr-model.png - :align: center - :alt: West multi-repo history - :figclass: align-center - - West multi-repo history - -The history of the manifest repository is the line of Git commits which is -"floating" on top of a plane (parent commits point to child commits using -solid arrows.) The plane contains the Git commit history of the projects, with -each project's history boxed in by a rectangle. - -The commits in the manifest repository (again, for upstream Zephyr this is the -zephyr repository itself) each have a manifest file. The manifest file in each -zephyr commit gives the corresponding commits which it expects in the other -projects. These are shown using dotted line arrows in the diagram. - -Notice a few important details about the above picture: - -- Other projects can stay at the same versions between two zephyr commits - (like ``P2`` does between zephyr commits ``A → B``, and both ``P1`` and - ``P3`` do in ``F → G``). -- Other projects can move forward in history between two zephyr commits (``P3`` - from ``A → B``). -- A project can also move backwards in its history as zephyr moves forward - (like ``P3`` from zephyr commits ``C → D``). One use for this is to "revert" - a regression by moving the other project to a version before it was - introduced. -- Not all zephyr manifests have the same other projects (``P2`` is not a part - of the installation at zephyr commits ``F`` and ``G``). -- Two zephyr commits can have the same external commits (like ``F`` and ``G``). -- Not all commits in some projects are associated with a zephyr commit (``P3`` - "jumps" multiple commits in its history between zephyr commits ``B → C``). -- Every zephyr commit's manifest refers to exactly one version in each of the - other projects it cares about. +A west installation, as described above, contains a clone of the west +repository in :file:`.west/west`. This is where the built-in command +implementations are currently provided. The rest of :ref:`West's APIs +` are also currently provided to extension commands by this +repository. So that west can update itself, the built-in ``west update`` and +``west selfupdate`` commands fetch and update the :file:`.west/west` repository. The ``manifest-rev`` branch *************************** West creates a branch named ``manifest-rev`` in each project, pointing to the -project's manifest revision (or, more specifically, to the commit the revision -resolves to). The ``manifest-rev`` branch is updated whenever project data is -fetched (the `command overview`_ below explains which commands fetch project -data). - -All work branches created using west track the ``manifest-rev`` branch. Several -multi-repo commands also use ``manifest-rev`` as a reference for the upstream -revision (as of the most recent fetch). +commit the project's revision resolves to. The branch is updated whenever +project data is fetched by ``west update``. Other multi-repo commands also use +``manifest-rev`` as a reference for the upstream revision as of the most recent +update. See :ref:`west-multi-repo-cmds`, below, for more information. + +``manifest-rev`` is a normal Git branch, but if you delete or otherwise modify +it, west will recreate and/or reset it as if with ``git reset --hard`` on the +next update (though ``git update-ref`` is used internally). For this reason, it +is normally a **bad idea to modify it yourself**. ``manifest-rev`` was added to +allow SHAs as project revisions in the manifest, and to give a consistent +reference for the current upstream revision regardless of how the manifest +changes over time. .. note:: - ``manifest-rev`` is a normal Git branch, and is only treated specially by - name. If you delete or otherwise modify it, it will be recreated/reset when - upstream data is next fetched by ``west``, as if through ``git reset - --hard`` (though ``git update-ref`` is used internally). - - Since ``manifest-rev`` represents the upstream revision as of the most - recent fetch, it is normally a bad idea to modify it. - - ``manifest-rev`` was added to allow branches to track SHA revisions, and to - give a consistent reference for the upstream revision regardless of how the - manifest changes over time. - -.. note:: West does not create a ``manifest-rev`` branch in the manifest repository, since west does not manage the manifest repository's branches or revisions. -Command overview -================ +.. _west-multi-repo-cmds: + +Multi-Repo Commands +******************* This section gives a quick overview of the multi-repo commands, split up by -functionality. Some commands loosely mimic the corresponding Git command, but in -a multi-repo context (``west diff`` shows local changes on all repositories). +functionality. Some commands loosely mimic the corresponding Git command, but +in a multi-repo context (e.g. ``west diff`` shows local changes on all +repositories). -Passing no projects to commands that accept a list of projects usually means to -run the command for all projects listed in the manifest. +Project arguments can be the names of projects in the manifest, or their paths +within the installation. Passing no project arguments to commands that accept a +list of projects usually means to use all projects in the manifest. .. note:: - For the most up-to-date documentation, see the command help texts (e.g. - ``west diff --help``). Only the most important flags are mentioned here. + For detailed help, see each command's ``--help`` output (e.g. ``west diff + --help``). -Cloning and updating projects -***************************** +Main Commands +============= -After running ``west init`` to initialize west (e.g., with the default Zephyr -manifest), the following commands will clone/update projects. +The ``west init`` and ``west update`` multi-repo commands are the most +important to understand. -.. note:: +- ``west init [-l] [-m URL] [--mr REVISION] [PATH]``: create a west + installation in directory :file:`PATH` (i.e. :file:`.west` etc. will be + created there). If the ``PATH`` argument is not given, the current working + directory is used. This command does not clone any of the projects in the + manifest; that is done the next time ``west update`` is run. - To implement self-updates, ``west init`` also clones a repository with the - west source code, which is updated whenever the projects are. The ``west`` - command is implemented as a thin wrapper that calls through to the code in - the cloned repository. The wrapper itself only implements the ``west init`` - command. - - This is the same model used by Google's ``repo`` tool. - -- ``west init [-l] [-m URL] [--mr REVISION] [PATH]``: Initializes a west - installation. - - This command can be invoked in two distinct ways. - If you already have a local copy or clone of the manifest repository, you can - use the ``-l`` switch to instruct west to initialize an installation around - the existing clone, without modifying it. For example, - ``west init -l path/to/zephyr`` is useful if you already have cloned the - zephyr repository in the past using Git and now want to initialize a west - installation around it. - If you however want to initialize an installation directly from the remote - repository, you have the option to specify its URL using the ``-m`` switch - and/or its revision with the ``--mr`` one. For example, invoking west with: - ``west init -m https://github.com/zephyrproject-rtos/zephyr --mr v1.15.0`` - would clone the upstream official zephyr repository at the tagged release - v1.15.0. - -- ``west update [PROJECT ...]``: Clones or updates the specified - projects (default: all projects). - - This command will parse the manifest file (:file:`west.yml`) in the manifest - repository, clone all project repositories that are not already present - locally and finally update all projects to the revision specified in the - manifest file. - An initial branch named after the project's manifest revision is created in - each cloned project repository. The names of branch and tag revisions are - used as-is. For qualified refs like ``refs/heads/foo``, the last component - (``foo``) is used. For SHA revisions, a detached ``HEAD`` is checked out. + This command can be invoked in two ways: -.. note:: - West uses ``git checkout`` to switch each project to the revision specified - in the manifest repository. This is typically a safe operation that will not - modify any branches or staged work you might have. + 1. If you already have a local clone of the zephyr repository and want to + create a west installation around it, you can use the ``-l`` switch to + pass its path to west, as in: ``west init -l path/to/zephyr``. + + 2. Otherwise, omit ``-l`` to create a new installation from a remote manifest + repository. You can give the manifest URL using the ``-m`` switch, and its + revision using ``--mr``. For example, invoking west with: ``west init -m + https://github.com/zephyrproject-rtos/zephyr --mr v1.15.0`` would clone + the upstream official zephyr repository at the tagged release v1.15.0 + (``-m`` defaults to https://github.com/zephyrproject-rtos/zephyr, and + ``--mr`` defaults to ``master``). -Miscellaneous commands -********************** +- ``west update [--rebase] [--keep-descendants] [--exclude-west] [PROJECT + ...]``: clone and update the specified projects (default: all projects) based + on the current :term:`west manifest`. -These commands perform miscellaneous functions. + This command parses the manifest, clones any project repositories that are + not already present locally, and checks out the project revisions specified + in the manifest file, updating ``manifest-rev`` branches along the way. + + For safety, ``west update`` uses ``git checkout --detach`` to check out a + detached ``HEAD`` at the manifest revision for each updated project, leaving + behind any branches which were already checked out. This is typically a safe + operation that will not modify any of your local branches. See the help for + the ``--rebase`` / ``-r`` and ``--keep-descendants`` / ``-k`` options for + ways to influence this. + + By default, ``west update`` also updates the west repository in the + installation. To prevent this, use ``--exclude-west``. + +Miscellaneous Commands +====================== + +West has a few more commands for managing the multi-repo, which are briefly +discussed here. - ``west list``: Lists project information from the manifest (URL, revision, path, etc.), along with other manifest-related information. -- ``west diff [PROJECT ...] [ARGUMENT ...]``: Runs a multi-repo ``git diff`` - for the specified projects (default: all cloned projects). +- ``west manifest --freeze [-o outfile]``: Save a "frozen" representation of + the current manifest; all ``revision`` fields are converted to SHAs based on + the current ``manifest-rev`` branches. - Extra arguments are passed as-is to ``git diff``. +- ``west diff [PROJECT ...]``: Runs a multi-repo ``git diff`` + for the specified projects (default: all cloned projects). -- ``west status [PROJECT ...] [ARGUMENT ...]``: Like ``west diff``, for +- ``west status [PROJECT ...]``: Like ``west diff``, for running ``git status``. - ``west forall -c COMMAND [PROJECT ...]``: Runs the shell command ``COMMAND`` within the top-level repository directory of each of the specified projects - (default: all cloned projects). - - If ``COMMAND`` consists of more than one word, it must be quoted to prevent - it from being split up by the shell. - - Note that ``west forall`` can be used to run any command, not just Git - commands. To run a Git command, do ``west forall -c 'git ...'``. + (default: all cloned projects). If ``COMMAND`` consists of more than one + word, it must be quoted to prevent it from being split up by the shell. -- ``west selfupdate``: Updates the west repository. + To run an arbitrary Git command in each project, use something like ``west + forall -c 'git --options'``. Note that ``west forall`` can be used + to run any command, though, not just Git commands. - Normally, the west repository is updated automatically whenever a command - that fetches upstream data is run (this behavior can be - suppressed for the duration of a single command by passing ``--no-update``). +- ``west selfupdate``: Updates the west repository in the installation. .. _PyPI: https://pypi.org/project/west/ diff --git a/doc/guides/west/sign.rst b/doc/guides/west/sign.rst new file mode 100644 index 00000000..e30c1e22 --- /dev/null +++ b/doc/guides/west/sign.rst @@ -0,0 +1,55 @@ +.. _west-sign: + +Signing Binaries +################ + +This page documents the ``west sign`` :ref:`extension ` +command included in the zephyr repository. It is used to sign a Zephyr +application binary for consumption by a bootloader using an external tool. + +Currently, it supports signing binaries for use with the `MCUboot`_ bootloader, +using the `imgtool`_ program provided by its developers. Using ``west sign`` as +a wrapper around ``imgtool`` for Zephyr binaries is more convenient than using +``imgtool`` directly, because ``west sign`` knows how to read numeric values +needed by ``imgtool`` out of an application build directory. These values +differ depending on your :ref:`board `, so using ``west sign`` means +both shorter command lines and not having to learn or memorize +hardware-specific details. + +To produce signed ``.bin`` and ``.hex`` files for a Zephyr application, make +sure ``imgtool`` is installed (e.g. with ``pip3 install imgtool`` on macOS and +Windows, and ``pip3 install --user imgtool`` on Linux), then run: + +.. code-block:: console + + west sign -t imgtool -d YOUR_BUILD_DIR -- --key YOUR_SIGNING_KEY.pem + +Above, :file:`YOUR_BUILD_DIR` is a Zephyr build directory containing an +application compiled for MCUboot (in practice, this means +:option:`CONFIG_BOOTLOADER_MCUBOOT` is ``y`` in the application's Kconfig). + +Some additional notes follow. See ``west sign -h`` for detailed help. + +- The default ``-d`` value is ``build``, which is the default output directory + created by :ref:`west build `. +- If you don't have your own signing key and have a default MCUboot build, use + ``--key path/to/mcuboot/root-rsa-2048.pem``. +- By default, the output files produced by ``west sign`` are named + :file:`zephyr.signed.bin` and :file:`zephyr.signed.hex`. You can control this + using the ``-B`` and ``-H`` options, e.g.: + + .. code-block:: console + + west sign -t imgtool -B my-signed.bin -H my-signed.hex [...] +- For reference, here is an example for how to build :ref:`hello_world` for + MCUboot using ``west build``: + + .. code-block:: console + + west build -b YOUR_BOARD zephyr/samples/hello_world -- -DCONFIG_BOOTLOADER_MCUBOOT=y + +.. _MCUboot: + https://mcuboot.com/ + +.. _imgtool: + https://pypi.org/project/imgtool/ diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 2a855cfe..1b2ed5a4 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -2,9 +2,94 @@ .. _west-apis: -West APIs -######### +West and Extension APIs +####################### + +This page documents the Python APIs provided by :ref:`west `, as well as +some additional APIs used by the :ref:`west extensions ` in +the zephyr repository. + +**Contents**: + +.. contents:: + :local: + +.. _west-apis-west: + +West +**** + +This section contains documentation for west's APIs. + +.. warning:: + + These APIs should be considered unstable until west version 1.0. Further, + until `west #38`_ is closed, these modules can only be imported from + extension command files (and within west itself, of course). + +.. NOTE: documentation authors: + + 1. keep these sorted by package/module name. + 2. if you add a :ref: target here, add it to west-not-found.rst too. + +.. _west-apis-commands: + +west.commands +============= + +.. automodule:: west.commands + :members: WestCommand, CommandError, CommandContextError, ExtensionCommandError + +.. _west-apis-configuration: + +west.configuration +================== + +.. automodule:: west.configuration + :members: ConfigFile, read_config, update_config + +.. _west-apis-log: + +west.log +======== + +.. automodule:: west.log + :members: set_verbosity, VERBOSE_NONE, VERBOSE_NORMAL, VERBOSE_VERY, VERBOSE_EXTREME, dbg, inf, wrn, err, die + +.. _west-apis-manifest: + +west.manifest +============= + +.. automodule:: west.manifest + :members: manifest_path, Manifest, Defaults, Remote, Project, SpecialProject, MalformedManifest, MalformedConfig, MANIFEST_SECTIONS, MANIFEST_PROJECT_INDEX, MANIFEST_REV_BRANCH, QUAL_MANIFEST_REV_BRANCH + +.. _west-apis-util: + +west.util +========= + +.. automodule:: west.util + :members: west_dir, west_topdir, WestNotFound + +.. _west-apis-zext: + +Zephyr Extensions +***************** + +This section contains documentation for APIs used by the extension commands +which are part of the Zephyr repository. In particular, it documents the +``runners.core`` module used by the :ref:`west-build-flash-debug` +commands. This is the core abstraction used to implement support for these +features. + +.. warning:: + + These APIs are provided for reference, but they are more "shared code" used + to implement multiple extension commands than a stable API. .. automodule:: runners.core :members: +.. _west #38: + https://github.com/zephyrproject-rtos/west/issues/38 diff --git a/doc/guides/west/west-not-found.rst b/doc/guides/west/west-not-found.rst index 1881f5c0..a584f6bf 100644 --- a/doc/guides/west/west-not-found.rst +++ b/doc/guides/west/west-not-found.rst @@ -1,6 +1,13 @@ :orphan: .. _west-apis: +.. _west-apis-west: +.. _west-apis-commands: +.. _west-apis-configuration: +.. _west-apis-log: +.. _west-apis-manifest: +.. _west-apis-util: +.. _west-apis-zext: West APIs ######### diff --git a/doc/guides/west/why.rst b/doc/guides/west/why.rst index ecfa0395..ea63135a 100644 --- a/doc/guides/west/why.rst +++ b/doc/guides/west/why.rst @@ -6,15 +6,124 @@ History and Motivation West was added to the Zephyr project to fulfill two fundamental requirements: * The ability to work with multiple Git repositories -* The ability to provide a user-friendly command-line interface to the Zephyr - build system and debug mechanisms - -Additionally, it was desired that west be easily extensible by -downstream users. +* The ability to provide an extensible and user-friendly command-line interface + for basic Zephyr workflows During the development of west, a set of :ref:`west-design-constraints` were identified to avoid the common pitfalls of tools of this kind. +Requirements +************ + +Although the motivation behind splitting the Zephyr codebase into multiple +repositories is outside of the scope of this page, the fundamental requirements, +along with a clear justification of the choice not to use existing tools and +instead develop a new one, do belong here. + +The basic requirements are: + +* **R1**: Keep externally maintained code in separately maintained repositories + outside of the main zephyr repository, without requiring users to manually + clone each of the external repositories +* **R2**: Provide a tool that both Zephyr users and distributors can make use of + to benefit from and extend +* **R3**: Allow users and downstream distributions to override or remove + repositories without having to make changes to the zephyr repository +* **R4**: Support both continuous tracking and commit-based (bisectable) project + updating + +Topologies supported +******************** + +The requirements above lead to three source code topologies supported by west: + +* **T1**: Star topology with zephyr as the manifest repository: + + - The zephyr repository acts as the central repository and includes a + complete list of projects used upstream + - Default (upstream) configuration + - Analogy with existing mechanisms: Git submodules with zephyr as the + superproject + - See :ref:`west-installation` for how mainline Zephyr is an example + of this topology + +* **T2**: Star topology with an application repository as the manifest + repository: + + - A repository containing a Zephyr application acts as the central repository + and includes a complete list of other projects, including the zephyr + repository, required to build it + - Useful for those focused on a single application + - Analogy with existing mechanisms: Git submodules with the application as + the superproject, zephyr and other projects as submodules + - An installation using this topology could look like this: + + .. code-block:: none + + app-manifest-installation + ├── application + │   ├── CMakeLists.txt + │   ├── prj.conf + │   ├── src + │   │   └── main.c + │   └── west.yml + ├── modules + │   └── lib + │   └── tinycbor + └── zephyr + +* **T3**: Forest topology: + + - A dedicated manifest repository which contains no Zephyr source code, + and specifies a list of projects all at the same "level" + - Useful for downstream distributions with no "central" repository + - Analogy with existing mechanisms: Google repo-based source distribution + - An installation using this topology could look like this: + + .. code-block:: none + + forest + ├── app1 + │   ├── CMakeLists.txt + │   ├── prj.conf + │   └── src + │   └── main.c + ├── app2 + │   ├── CMakeLists.txt + │   ├── prj.conf + │   └── src + │   └── main.c + ├── manifest-repo + │   └── west.yml + ├── modules + │   └── lib + │   └── tinycbor + └── zephyr + +Rationale for a custom tool +*************************** + +Existing tools were considered during west's initial design and development. +None were found suitable for Zephyr's requirements. In particular, these were +examined in detail: + +* Google repo + + - Does not cleanly support using zephyr as the manifest repository (**R4**) + - Python 2 only + - Does not play well with Windows + - Assumes Gerrit is used for code review + +* Git submodules + + - Does not fully support **R1**, since the externally maintained repositories + would still need to be inside the main zephyr Git tree + - Does not support **R3**, since downstream copies would need to either + delete or replace submodule definitions + - Does not support continuous tracking of the latest ``HEAD`` in external + repositories (**R4**) + - Requires hardcoding of the paths/locations of the external repositories + Multiple Git Repositories ************************* From bc76ca905beb59f204b3bbb009efab8c8a4ea265 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 2 Apr 2019 13:55:25 -0600 Subject: [PATCH 022/226] doc: additional clarifications on west Add a missing reference to how west is used to set ZEPHYR_MODULES in without-west.rst, augmenting the application development guide a bit to include this in the list of important variables, cleaning that up a bit while we are here and adding some more west details. Add a big fat warning in the getting started guide that using Zephyr without west is not for the faint of heart. Signed-off-by: Marti Bolivar --- doc/guides/west/index.rst | 16 ++++-- doc/guides/west/repo-tool.rst | 2 + doc/guides/west/without-west.rst | 93 ++++++++++++++++++++++++++------ 3 files changed, 90 insertions(+), 21 deletions(-) diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 4204aaa3..91cf5f83 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -11,11 +11,17 @@ sub-command:: west [common-opts] [opts] -West's built-in commands provide a multiple repository management system with -features inspired by Google's Repo tool and Git submodules. West is also -pluggable: you can write your own west "extension commands" which add -additional features to west. Zephyr provides extension commands for building -applications, debugging them, and more. +West's built-in commands provide a multiple repository management +system with features inspired by Google's Repo tool and Git +submodules. West simplifies configuration and is also pluggable: you +can write your own west "extension commands" which add additional +features to west. Zephyr uses this feature to provide conveniences +for building applications, flashing and debugging them, and more. + +It is possible not to use west for Zephyr development if you do not +require these features, prefer to use your own tools, or want to +eliminate the extra layer of indirection. However, this implies extra +effort and expert knowledge. You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index c85fbf90..20a44976 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -226,6 +226,8 @@ important to understand. By default, ``west update`` also updates the west repository in the installation. To prevent this, use ``--exclude-west``. +.. _west-multi-repo-misc: + Miscellaneous Commands ====================== diff --git a/doc/guides/west/without-west.rst b/doc/guides/west/without-west.rst index ce38c068..23d8095c 100644 --- a/doc/guides/west/without-west.rst +++ b/doc/guides/west/without-west.rst @@ -3,30 +3,75 @@ Using Zephyr without west ######################### -There are many valid usecases to avoid using a meta-tool such as west which has -been custom-designed for a particular project and its requirements. -This section applies to Zephyr users who fall into one or more of these -categories: +This page provides information on using Zephyr without west. This is +not recommended for beginners due to the extra effort involved. In +particular, you will have to do work "by hand" to replace these +features: -- Already use a multi-repository management system (for example Google repo) +- cloning the additional source code repositories used by Zephyr in + addition to the main zephyr repository, and keeping them up to date +- specifying the locations of these repositories to the Zephyr build + system +- flashing and debugging without understanding detailed usage of the + relevant host tools -- Do not need additional functionality beyond compiling and linking +.. note:: -In order to obtain the Zephyr source code and build it without the help of -west you will need to manually clone the repositories listed in the -`manifest file`_ one by one, at the path indicated in it. + If you have previously installed west and want to stop using it, + uninstall it first: + + .. code-block:: console + + pip3 uninstall west + + Otherwise, Zephyr's build system will find it and may try to use + it. + +Getting the Source +------------------ + +In addition to downloading the zephyr source code repository itself, +you will need to manually clone the additional projects listed in the +:term:`west manifest` file inside that repository. .. code-block:: console mkdir zephyrproject cd zephyrproject git clone https://github.com/zephyrproject-rtos/zephyr - # clone additional repositories listed in the manifest file, - # and check out the specified revisions + # clone additional repositories listed in zephyr/west.yml, + # and check out the specified revisions as well. + +As you pull changes in the zephyr repository, you will also need to +maintain those additional repositories, adding new ones as necessary +and keeping existing ones up to date at the latest revisions. + +Specifying Modules +------------------ -If you want to manage Zephyr's repositories without west but still need to -use west's additional functionality (flashing, debugging, etc.) it is possible -to do so by manually creating an installation: +If you have west installed, the Zephyr build system will use it to set +:ref:`ZEPHYR_MODULES `. If you don't have west +installed and your application does not need any of these +repositories, the build will still work. + +If you don't have west installed and your application *does* need one +of these repositories, you must set :makevar:`ZEPHYR_MODULES` +yourself. See :ref:`ext-projs` for details. + +Flashing and Debugging +---------------------- + +Running build system targets like ``ninja flash``, ``ninja debug``, +etc. is just a call to the corresponding :ref:`west command +`. For example, ``ninja flash`` calls ``west +flash``\ [#wbninja]_. If you don't have west installed on your system, running +those targets will fail. You can of course still flash and debug using +any :ref:`debug-host-tools` which work for your board (and which those +west commands wrap). + +If you want to use these build system targets but do not want to +install west on your system using ``pip``, it is possible to do so +by manually creating a :term:`west installation`: .. code-block:: console @@ -40,11 +85,27 @@ Then create a file :file:`.west/config` with the following contents: [manifest] path = zephyr + [zephyr] + base = zephyr + After that, and in order for ``ninja`` to be able to invoke ``west`` to flash and debug, you must specify the west directory. This can be done by setting the environment variable ``WEST_DIR`` to point to :file:`zephyrproject/.west/west` before running CMake to set up a build directory. -.. _manifest file: - https://github.com/zephyrproject-rtos/zephyr/blob/master/west.yml +.. rubric:: Footnotes + +.. [#wbninja] + + Note that ``west build`` invokes ``ninja``, among other + tools. There's no recursive invocation of either ``west`` or + ``ninja`` involved by default, however, as ``west build`` does not + invoke ``ninja flash``, ``debug``, etc. The one exception is if you + specifically run one of these build system targets with a command + line like ``west build -t flash``. In that case, west is run twice: + once for ``west build``, and in a subprocess, again for ``west + flash``. Even in this case, ``ninja`` is only run once, as ``ninja + flash``. This is because these build system targets depend on an + up to date build of the Zephyr application, so it's compiled before + ``west flash`` is run. From e9b24d8fa599154805ff172b25591275d4a342d0 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Thu, 4 Apr 2019 15:39:19 +0200 Subject: [PATCH 023/226] doc: add example of how to build MCUBoot app with west This commit extends existing documentation by providing an example of how to build Hello World sample application for MCUboot using west. Signed-off-by: Piotr Mienkowski --- doc/guides/west/sign.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/sign.rst b/doc/guides/west/sign.rst index e30c1e22..d381e8d4 100644 --- a/doc/guides/west/sign.rst +++ b/doc/guides/west/sign.rst @@ -41,12 +41,19 @@ Some additional notes follow. See ``west sign -h`` for detailed help. .. code-block:: console west sign -t imgtool -B my-signed.bin -H my-signed.hex [...] -- For reference, here is an example for how to build :ref:`hello_world` for - MCUboot using ``west build``: - .. code-block:: console +Example build flow +****************** +For reference, here is an example showing how to build :ref:`hello_world` for +MCUboot using ``west``: + +.. code-block:: console + + west build -b YOUR_BOARD samples/hello_world -- -DCONFIG_BOOTLOADER_MCUBOOT=y + west sign -t imgtool -- --key YOUR_SIGNING_KEY.pem + west flash --hex-file zephyr.signed.hex - west build -b YOUR_BOARD zephyr/samples/hello_world -- -DCONFIG_BOOTLOADER_MCUBOOT=y +Availability of a hex file depends on your build configuration. .. _MCUboot: https://mcuboot.com/ From 015d75f72847e5a089325a17cad668e05eff30a6 Mon Sep 17 00:00:00 2001 From: "David B. Kinder" Date: Wed, 10 Apr 2019 14:57:51 -0700 Subject: [PATCH 024/226] doc: add missing doc top labels All docs should have a label at the top that would permit cross-document linking via :ref:`labelname`. Update "testing" label that would have conflicted and fix the only reference to the old "testing" label in development process documentation. Signed-off-by: David B. Kinder --- doc/guides/west/planned.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/guides/west/planned.rst b/doc/guides/west/planned.rst index 81582645..11d5dcbb 100644 --- a/doc/guides/west/planned.rst +++ b/doc/guides/west/planned.rst @@ -1,3 +1,5 @@ +.. _west-planned-features: + Planned Features ================ From 6b65d3cae6ee08219d4389c3d66401040cc8f84f Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Sun, 14 Apr 2019 21:52:45 +0200 Subject: [PATCH 025/226] west: build: Add new pristine cmd-line and config option Add a new command-line and build config option, `pristine`, that the user can pass to `west build` or set in its configuration file(s) in order to automatically trigger a pristine build on every build or whenever west considers it required. The option can take the following values: - never: Never run the target - always: Always run the pristine target before building - auto: Run the pristine target when required With `auto`, the pristine target will be run when running west with an existing build folder containing a build system and: - Selecting a different board from the one currently in the build system - Selecting a different application from the one currently in the build system Signed-off-by: Carles Cufi --- doc/guides/west/build-flash-debug.rst | 12 ++++++++++++ doc/guides/west/config.rst | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 6518b3e4..afc67231 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -73,6 +73,18 @@ Additionally you can specify the build system target using the ``--target`` You can list all targets with ``ninja help`` (or ``west build -t help``) inside the build folder. +A clean build can be triggered by using the ``--pristine`` (or ``-p``) option. +This is particularly handy if you want to switch source dirs or boards without +using a different build dir:: + + west build -b qemu_x86 samples/philosophers + west build -p -b reel_board samples/hello_world + +If you are unsure about whether the command-line parameters you supply to +``west build`` require a clean build you can let west decide for you by using +the ``auto`` setting in the ``--pristine`` option:: + + west build -p auto -b reel_board samples/hello_world Finally, you can add additional arguments to the CMake invocation performed by ``west build`` by supplying additional parameters (after a ``--``) to the diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index 6f7bb389..4618c7d5 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -150,3 +150,29 @@ commands. environment overrides the value of the ``zephyr.base`` configuration option. If set to ``"configfile"``, the configuration option wins instead. + +Zephyr Extension Commands Configuration Options +----------------------------------------------- + +The following table documents configuration options supported by zephyr's +extension commands (found in :file:`scripts/west_commands`). +.. NOTE: docs authors: keep this table sorted by section, then option. + +.. list-table:: + :widths: 10 30 + :header-rows: 1 + + * - Option + - Description + * - ``build.pristine`` + - String. Controls the way in which ``west build`` may run the ``pristine`` + target before building. Can take the following values: + + - ``never`` (default): Never automatically run the ``pristine`` target. + - ``auto``: ``west build`` will automatically run the ``pristine`` + target before building, if a build system is present and the build + will fail otherwise (e.g. the user has specified a different board or + application from the one previously used to make the build + directory). + - ``always``: Always run the ``pristine`` target before building, if + a build system is present. From 007d1dbf4549a996cc04e9dfa4362bf5671eea35 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 18 Apr 2019 16:46:12 +0200 Subject: [PATCH 026/226] scripts: west: Run pristine.cmake directly instead of the target When making a build folder pristine until now we were running the 'pristine' build target. The issue with that is that ninja/make or whatever build tool is being used might decide to re-run CMake itself if some of the dependencies have changes. This might trigger an error that is unfriendly and unnecessary, since the user is explicitly asking for the build folder to be wiped before starting a fresh build. To avoid this issue restor to running directly the CMake script that the 'pristine' build target itself uses, so as to make sure that the build folder is wiped unconditionally regardless of changes made to the tree. Signed-off-by: Carles Cufi --- doc/guides/west/config.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index 4618c7d5..d165afac 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -165,14 +165,15 @@ extension commands (found in :file:`scripts/west_commands`). * - Option - Description * - ``build.pristine`` - - String. Controls the way in which ``west build`` may run the ``pristine`` - target before building. Can take the following values: - - - ``never`` (default): Never automatically run the ``pristine`` target. - - ``auto``: ``west build`` will automatically run the ``pristine`` - target before building, if a build system is present and the build - will fail otherwise (e.g. the user has specified a different board or - application from the one previously used to make the build + - String. Controls the way in which ``west build`` may clean the build + folder before building. Can take the following values: + + - ``never`` (default): Never automatically make the build folder + pristine. + - ``auto``: ``west build`` will automatically make the build folder + pristine before building, if a build system is present and the build + would fail otherwise (e.g. the user has specified a different board + or application from the one previously used to make the build directory). - - ``always``: Always run the ``pristine`` target before building, if + - ``always``: Always make the build folder pristine before building, if a build system is present. From 87ec07f1d231c7c2444f50b9478c884778cbe6e9 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 23 Apr 2019 22:34:40 +0200 Subject: [PATCH 027/226] west: Add a boards command Add a new "boards" command that is able to list all the boards in the upstream tree. There is currently no support for out-of-tree boards. The command executes cmake to use the built-in CMake script, boards.cmake, to list the boards, and then stores the information retrieved and allows the user to present it in a user-definable format. Fixes https://github.com/zephyrproject-rtos/west/issues/53 Signed-off-by: Carles Cufi --- doc/guides/west/build-flash-debug.rst | 10 ++++--- doc/guides/west/extensions.rst | 6 +++-- doc/guides/west/index.rst | 1 + doc/guides/west/zephyr-cmds.rst | 39 +++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 doc/guides/west/zephyr-cmds.rst diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index afc67231..b04448e3 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -3,9 +3,9 @@ Building, Flashing and Debugging ################################ -West provides 5 commands for building, flashing, and interacting with Zephyr -programs running on a board: ``build``, ``flash``, ``debug``, ``debugserver`` -and ``attach``. +Zephyr provides several :ref:`west extension commands ` for +building, flashing, and interacting with Zephyr programs running on a board: +``build``, ``flash``, ``debug``, ``debugserver`` and ``attach``. These use information stored in the CMake cache [#cmakecache]_ to flash or attach a debugger to a board supported by Zephyr. The exception is @@ -61,6 +61,10 @@ no additional parameters. whether ``-b`` is required, just try leaving it out. West will print an error if the option is required and was not given. +.. tip:: + You can use the :ref:`west boards ` command to list all + supported boards. + Specify the source directory path as the first positional argument:: west build -b path/to/source/directory diff --git a/doc/guides/west/extensions.rst b/doc/guides/west/extensions.rst index f770c664..dd35f563 100644 --- a/doc/guides/west/extensions.rst +++ b/doc/guides/west/extensions.rst @@ -11,12 +11,14 @@ information on west extension commands, and has a tutorial for writing your own. Some commands you can run when using west with Zephyr, like the ones used to -:ref:`build, flash, and debug `, are extensions. That's -why help for them shows up like this in ``west --help``: +:ref:`build, flash, and debug ` and the +:ref:`ones described here ` , are extensions. That's why +help for them shows up like this in ``west --help``: .. code-block:: none commands from project at "zephyr": + boards: display information about supported boards build: compile a Zephyr application sign: sign a Zephyr binary for bootloader chain-loading flash: flash and run a binary on a board diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 91cf5f83..b17931e7 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -38,6 +38,7 @@ context about the tool. config.rst extensions.rst build-flash-debug.rst + zephyr-cmds.rst sign.rst why.rst without-west.rst diff --git a/doc/guides/west/zephyr-cmds.rst b/doc/guides/west/zephyr-cmds.rst new file mode 100644 index 00000000..92f0b6a3 --- /dev/null +++ b/doc/guides/west/zephyr-cmds.rst @@ -0,0 +1,39 @@ +.. _west-zephyr-ext-cmds: + +Additional Zephyr extension commands +#################################### + +Aside from the :ref:`build, flash, and debug commands `, +the zephyr tree extends the west command set with additional zephyr-specific +commands. + +.. Add a per-page contents at the top of the page. This page is nested + deeply enough that it doesn't have any subheadings in the main nav. + +.. only:: html + + .. contents:: + :local: + +.. _west-boards: + +Listing boards: ``west boards`` +******************************* + +The ``boards`` command can be used to list the boards that are supported by +Zephyr without having to resort to additional sources of information. + +It can be run by typing:: + + west boards + +This command lists all supported boards in a default format. If you prefer to +specify the display format yourself you can use the ``--format`` (or ``-f``) +flag:: + + west boards -f "{arch}:{name}" + +Additional help about the formatting options can be found by running:: + + west boards -h + From d3793721920f70ec27488e71db817b0d01e7d88b Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sat, 4 May 2019 13:14:57 -0600 Subject: [PATCH 028/226] scripts: improve west build's board handling - Respect the BOARD environment setting. - Don't require --force if the board can't be figured out: it might be set in CMakeLists.txt, for example. Instead, downgrade to a warning which can be disabled with "west config build.board_warn false". - Add a build.board configuration option used as a final BOARD fallback after CACHED_BOARD (in the CMake cache), --board (command line), and BOARD (environment). - Keep the config docs up to date. Signed-off-by: Marti Bolivar --- doc/guides/west/config.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index d165afac..8e4dcbd9 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -156,6 +156,7 @@ Zephyr Extension Commands Configuration Options The following table documents configuration options supported by zephyr's extension commands (found in :file:`scripts/west_commands`). + .. NOTE: docs authors: keep this table sorted by section, then option. .. list-table:: @@ -164,6 +165,13 @@ extension commands (found in :file:`scripts/west_commands`). * - Option - Description + * - ``build.board`` + - String. If given, this the board used by :ref:`west build + ` when ``--board`` is not given and :envvar:`BOARD` + is unset in the environment. + * - ``build.board_warn`` + - Boolean, default ``true``. If ``false``, disables warnings when + ``west build`` can't figure out the target board. * - ``build.pristine`` - String. Controls the way in which ``west build`` may clean the build folder before building. Can take the following values: From 0b9b48da197d289af87dd5cbd24110684328bbb8 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 1 May 2019 16:30:58 -0600 Subject: [PATCH 029/226] doc: re-word and extend west build documentation Try to make the language simpler. Introduce each example with a paragraph that says "To " to make them easier to find. Move the config options to the documentation for that command to make them easier to find. Add some more examples for use cases we've gotten questions about. Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 161 ++++++++++++++++++-------- doc/guides/west/config.rst | 40 +------ 2 files changed, 116 insertions(+), 85 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index b04448e3..3e302c07 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -29,86 +29,151 @@ Building: ``west build`` .. tip:: Run ``west build -h`` for additional help. -The ``build`` command allows you to build any source tree from any directory -in your file system, placing the build results in a folder of your choice. +The ``build`` command helps you build Zephyr applications from source. You can +use :ref:`west config ` to configure its behavior. -In its simplest form, the command can be run by navigating to the root folder -(i.e. the folder containing a :file:`CMakeLists.txt` file) of the Zephyr -application of your choice and running:: +Basics +====== + +The easiest way to use it is to go to an application's root directory (i.e. the +folder containing its :file:`CMakeLists.txt`) and then run:: west build -b Where ```` is the name of the board you want to build for. This is exactly the same name you would supply to CMake if you were to invoke it with: ``cmake -DBOARD=``. -A build folder named :file:`build` (default name) will be created and the -build output will be placed in it. -To specify the build directory, use ``--build-dir`` (or ``-d``):: +.. tip:: - west build -b --build-dir path/to/build/directory + You can use the :ref:```west boards`` ` command to list all + supported boards. -Since the build directory defaults to :file:`build`, if you do not specify -a build directory but a folder named :file:`build` is present, that will be used, -allowing you to incrementally build from outside the :file:`build` folder with -no additional parameters. +A build directory named :file:`build` will be created, and the application will +be compiled there after ``west build`` runs CMake to create a build system in +that directory. If you run ``west build`` with an existing build directory, the +application is incrementally re-compiled without re-running CMake. -.. note:: - The ``-b `` parameter is only required when there is no CMake cache - present at all, usually when you are building from scratch or creating a - brand new build directory. After that you can rebuild (even with additional - parameters) without having to specify the board again. If you're unsure - whether ``-b`` is required, just try leaving it out. West will print an - error if the option is required and was not given. +You don't need to give ``-b`` if you've already got an existing build +directory; ``west build`` can figure out the board from the CMake cache. For +new builds, the :envvar:`BOARD` environment variable and ``build.board`` +configuration option can also be used to set the board. -.. tip:: - You can use the :ref:`west boards ` command to list all - supported boards. +To configure ``west build`` to build for the ``reel_board`` by default:: + + west config build.board reel_board -Specify the source directory path as the first positional argument:: +(You can use any other board supported by Zephyr here; it doesn't have to be +``reel_board``.) + +To use another build directory, use ``--build-dir`` (or ``-d``):: + + west build -b --build-dir path/to/build/directory + +To specify the application source directory explicitly, give its path as a +positional argument:: west build -b path/to/source/directory -Additionally you can specify the build system target using the ``--target`` -(or ``-t``) option. For example, to run the ``clean`` target:: +To specify the build system target to run, use ``--target`` (or ``-t``). + +For example, on host platforms with QEMU, you can use the ``run`` target to +build and run the :ref:`hello_world` sample for the emulated :ref:`qemu_x86 +` board in one command:: - west build -t clean + west build -b qemu_x86 -t run samples/hello_world -You can list all targets with ``ninja help`` (or ``west build -t help``) inside -the build folder. +As another example, to use ``-t`` to list all build system targets:: -A clean build can be triggered by using the ``--pristine`` (or ``-p``) option. -This is particularly handy if you want to switch source dirs or boards without -using a different build dir:: + west build -t help + +As a final example, to use ``-t`` to run the ``pristine`` target, which deletes +all the files in the build directory:: + + west build -t pristine + +To have ``west build`` run the ``pristine`` target before re-running CMake to +generate a build system, use the ``--pristine`` (or ``-p``) option. For +example, to switch board and application (which requires a pristine build +directory) in one command:: west build -b qemu_x86 samples/philosophers west build -p -b reel_board samples/hello_world -If you are unsure about whether the command-line parameters you supply to -``west build`` require a clean build you can let west decide for you by using -the ``auto`` setting in the ``--pristine`` option:: +To let west decide for you if a pristine build is needed, use ``-p auto``:: west build -p auto -b reel_board samples/hello_world -Finally, you can add additional arguments to the CMake invocation performed by -``west build`` by supplying additional parameters (after a ``--``) to the -command. For example, to use the Unix Makefiles CMake generator instead of -Ninja (which ``west build`` uses by default), run:: +.. tip:: + + You can run ``west config build.pristine auto`` to make this setting + permanent. + +To add additional arguments to the CMake invocation performed by ``west +build``, pass them after a ``--`` at the end of the command line. + +For example, to use the Unix Makefiles CMake generator instead of Ninja (which +``west build`` uses by default), run:: - west build -b reel_board samples/hello_world -- -G'Unix Makefiles' + west build -b reel_board -- -G'Unix Makefiles' -As another example, and assuming you have already built a sample, the following -command adds the ``file.conf`` Kconfig fragment to the files which are merged -into your final build configuration:: +.. note:: + + Passing additional CMake arguments like this forces ``west build`` to re-run + CMake, even if a build system has already been generated. + +As another example, to use Unix Makefiles and enable the +`CMAKE_VERBOSE_MAKEFILE`_ option:: + + west build -b reel_board -- -G'Unix Makefiles' -DCMAKE_VERBOSE_MAKEFILE=ON + +Notice how the ``--`` only appears once, even though multiple CMake arguments +are given. All command-line arguments to ``west build`` after a ``--`` are +passed to CMake. + +As a final example, to merge the :file:`file.conf` Kconfig fragment into your +build's :file:`.config`:: west build -- -DOVERLAY_CONFIG=file.conf -Passing additional CMake arguments like this forces ``west build`` to re-run -CMake, even if a build system has already been generated. You can also force -a CMake re-run using the ``-c`` (or ``--cmake``) option:: +To force a CMake re-run, use the ``--cmake`` (or ``--c``) option:: west build -c +Configuration Options +===================== + +You can :ref:`configure ` ``west build`` using these options. + +.. NOTE: docs authors: keep this table sorted alphabetically + +.. list-table:: + :widths: 10 30 + :header-rows: 1 + + * - Option + - Description + * - ``build.board`` + - String. If given, this the board used by :ref:`west build + ` when ``--board`` is not given and :envvar:`BOARD` + is unset in the environment. + * - ``build.board_warn`` + - Boolean, default ``true``. If ``false``, disables warnings when + ``west build`` can't figure out the target board. + * - ``build.pristine`` + - String. Controls the way in which ``west build`` may clean the build + folder before building. Can take the following values: + + - ``never`` (default): Never automatically make the build folder + pristine. + - ``auto``: ``west build`` will automatically make the build folder + pristine before building, if a build system is present and the build + would fail otherwise (e.g. the user has specified a different board + or application from the one previously used to make the build + directory). + - ``always``: Always make the build folder pristine before building, if + a build system is present. + .. _west-flashing: Flashing: ``west flash`` @@ -376,5 +441,5 @@ commands do it). .. _cmake(1): https://cmake.org/cmake/help/latest/manual/cmake.1.html -.. _namespace package: - https://www.python.org/dev/peps/pep-0420/ +.. _CMAKE_VERBOSE_MAKEFILE: + https://cmake.org/cmake/help/latest/variable/CMAKE_VERBOSE_MAKEFILE.html diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index 8e4dcbd9..67c3758d 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -118,8 +118,9 @@ To undo the above change: Built-in Configuration Options ------------------------------ -The following table documents configuration options supported by west's built-in -commands. +The following table documents configuration options supported by west's +built-in commands. Configuration options supported by Zephyr's extension +commands are documented in the pages for those commands. .. NOTE: docs authors: keep this table sorted by section, then option. @@ -150,38 +151,3 @@ commands. environment overrides the value of the ``zephyr.base`` configuration option. If set to ``"configfile"``, the configuration option wins instead. - -Zephyr Extension Commands Configuration Options ------------------------------------------------ - -The following table documents configuration options supported by zephyr's -extension commands (found in :file:`scripts/west_commands`). - -.. NOTE: docs authors: keep this table sorted by section, then option. - -.. list-table:: - :widths: 10 30 - :header-rows: 1 - - * - Option - - Description - * - ``build.board`` - - String. If given, this the board used by :ref:`west build - ` when ``--board`` is not given and :envvar:`BOARD` - is unset in the environment. - * - ``build.board_warn`` - - Boolean, default ``true``. If ``false``, disables warnings when - ``west build`` can't figure out the target board. - * - ``build.pristine`` - - String. Controls the way in which ``west build`` may clean the build - folder before building. Can take the following values: - - - ``never`` (default): Never automatically make the build folder - pristine. - - ``auto``: ``west build`` will automatically make the build folder - pristine before building, if a build system is present and the build - would fail otherwise (e.g. the user has specified a different board - or application from the one previously used to make the build - directory). - - ``always``: Always make the build folder pristine before building, if - a build system is present. From 0ba8791563af96811adebf7c61a1b1ae1bfe5a98 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 1 May 2019 16:53:32 -0600 Subject: [PATCH 030/226] scripts: add build.generator config option for west build This can be used to override the default CMake generator permanently. Its values are the same as those acceptable to cmake's -G option. Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 3e302c07..b479e450 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -109,6 +109,8 @@ To let west decide for you if a pristine build is needed, use ``-p auto``:: You can run ``west config build.pristine auto`` to make this setting permanent. +.. _west-building-generator: + To add additional arguments to the CMake invocation performed by ``west build``, pass them after a ``--`` at the end of the command line. @@ -160,6 +162,10 @@ You can :ref:`configure ` ``west build`` using these options. * - ``build.board_warn`` - Boolean, default ``true``. If ``false``, disables warnings when ``west build`` can't figure out the target board. + * - ``build.generator`` + - String, default ``Ninja``. The `CMake Generator`_ to use to create a + build system. (To set a generator for a single build, see the + :ref:`above example `) * - ``build.pristine`` - String. Controls the way in which ``west build`` may clean the build folder before building. Can take the following values: @@ -443,3 +449,6 @@ commands do it). .. _CMAKE_VERBOSE_MAKEFILE: https://cmake.org/cmake/help/latest/variable/CMAKE_VERBOSE_MAKEFILE.html + +.. _CMake Generator: + https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html From 841b0d775695c664f3ac45e1111c55c3681bbe80 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sat, 4 May 2019 13:56:36 -0600 Subject: [PATCH 031/226] scripts: make west build -h fit on a screen The west build --help output no longer fits in a single page. Move details and examples into the documentation, so the -h output doesn't require scrolling around. Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 33 ++++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index b479e450..7296984a 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -27,16 +27,31 @@ directly delegate to West. Building: ``west build`` ************************ -.. tip:: Run ``west build -h`` for additional help. +.. tip:: Run ``west build -h`` for a quick overview. The ``build`` command helps you build Zephyr applications from source. You can use :ref:`west config ` to configure its behavior. +This command attempts to "do what you mean" when run from a Zephyr application +source or build directory: + +- When you run ``west build`` in an existing build directory, the board, source + directory, etc. are obtained from the CMake cache, and that build directory + is re-compiled. + +- The same is true if a Zephyr build directory named :file:`build` exists in + your current working directory. + +- Otherwise, the source directory defaults to the current working directory, so + running ``west build`` from a Zephyr application's source directory compiles + it. + Basics ====== -The easiest way to use it is to go to an application's root directory (i.e. the -folder containing its :file:`CMakeLists.txt`) and then run:: +The easiest way to use ``west build`` is to go to an application's root +directory (i.e. the folder containing the application's :file:`CMakeLists.txt`) +and then run:: west build -b @@ -52,12 +67,13 @@ exactly the same name you would supply to CMake if you were to invoke it with: A build directory named :file:`build` will be created, and the application will be compiled there after ``west build`` runs CMake to create a build system in that directory. If you run ``west build`` with an existing build directory, the -application is incrementally re-compiled without re-running CMake. +application is incrementally re-compiled without re-running CMake (you can +force CMake to run again with ``--cmake``). -You don't need to give ``-b`` if you've already got an existing build -directory; ``west build`` can figure out the board from the CMake cache. For -new builds, the :envvar:`BOARD` environment variable and ``build.board`` -configuration option can also be used to set the board. +You don't need to use the ``--board`` option if you've already got an existing +build directory; ``west build`` can figure out the board from the CMake cache. +For new builds, the ``--board`` option, :envvar:`BOARD` environment variable, +or ``build.board`` configuration option are checked (in that order). To configure ``west build`` to build for the ``reel_board`` by default:: @@ -109,6 +125,7 @@ To let west decide for you if a pristine build is needed, use ``-p auto``:: You can run ``west config build.pristine auto`` to make this setting permanent. + .. _west-building-generator: To add additional arguments to the CMake invocation performed by ``west From 0dd3df0728fa078d95eb2e68abc626e3655fed06 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sat, 4 May 2019 14:13:15 -0600 Subject: [PATCH 032/226] doc: fix west boards tip Doc fix for an unaddressed review comment from when the feature was first merged. Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 7296984a..724a1137 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -61,7 +61,7 @@ exactly the same name you would supply to CMake if you were to invoke it with: .. tip:: - You can use the :ref:```west boards`` ` command to list all + You can use the :ref:`west boards ` command to list all supported boards. A build directory named :file:`build` will be created, and the application will From 3f38af8595b45e8ac8f0681532f321e5d86b584e Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Wed, 8 May 2019 18:05:38 +0200 Subject: [PATCH 033/226] west: Add completion command Add a completion command that dumps the contents of a shell completion file present in the zephyr repository. Signed-off-by: Carles Cufi --- doc/guides/west/extensions.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/guides/west/extensions.rst b/doc/guides/west/extensions.rst index dd35f563..00a29c35 100644 --- a/doc/guides/west/extensions.rst +++ b/doc/guides/west/extensions.rst @@ -18,6 +18,7 @@ help for them shows up like this in ``west --help``: .. code-block:: none commands from project at "zephyr": + completion: display shell completion scripts boards: display information about supported boards build: compile a Zephyr application sign: sign a Zephyr binary for bootloader chain-loading From f67b0ab3551496d9cbd9c5aed63f02afb1ffe7a8 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Wed, 8 May 2019 18:07:01 +0200 Subject: [PATCH 034/226] doc: west: Document west installation in-depth Create a new dedicated section for west installation that details some of the finer aspects of the process and steps involved. Signed-off-by: Carles Cufi --- doc/guides/west/index.rst | 1 + doc/guides/west/install.rst | 96 +++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 doc/guides/west/install.rst diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index b17931e7..eabbc0c3 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -33,6 +33,7 @@ context about the tool. .. toctree:: :maxdepth: 1 + install.rst repo-tool.rst manifest.rst config.rst diff --git a/doc/guides/west/install.rst b/doc/guides/west/install.rst new file mode 100644 index 00000000..0b2d30b6 --- /dev/null +++ b/doc/guides/west/install.rst @@ -0,0 +1,96 @@ +.. _west-install: + +Installing west +############### + +West is written in Python 3 and distributed through `PyPI`_. +Use :file:`pip3` to install or upgrade west: + +On Linux:: + + pip3 install --user -U west + +On Windows and macOS:: + + pip3 install -U west + +.. note:: + See :ref:`gs_python_deps` for additional clarfication on using the + ``--user`` switch. + +The following are the typical locations where the west files will be +installed if you followed the instructions above: + +.. tip:: + You can use the ``pip3 show -f west`` command to display information about + the installed packaged, including file locations. + +* Linux: + + * Executable: :file:`~/.local/bin/west` + * Package: :file:`~/.local/lib/python3./site-packages/west/` + +* macOS: + + * Executable: :file:`/usr/local/bin/west` + * Package: :file:`/usr/local/lib/python3./site-packages/west/` + +* Windows: + + * Executable: :file:`C:\\Python3\\Scripts\\west.exe` + * Package: :file:`C:\\Python3\\Lib\\site-packages\\west\\` + +Once west is installed you can use it to :ref:`clone the Zephyr repositories +`. + +.. _west-shell-completion: + +Enabling shell completion +************************* + +West currently supports shell completion in the following combinations of +platform and shell: + +* Linux: bash +* macOS: bash +* Windows: not available + +In order to enable shell completion, you will need to obtain the corresponding +completion script and have it sourced every time you enter a new shell session. + +To obtain the completion script you can use the ``west completion`` command:: + + cd ~ + west completion bash > west-completion.bash + +.. note:: + Remember to update the completion script using ``west completion`` regularly + to always have an up to date copy of it. + +Next you need to have it sourced. + +On Linux you have the following options: + +* Copy :file:`west-completion.bash` to :file:`/etc/bash_completion.d/` +* Copy :file:`west-completion.bash` to :file:`/usr/share/bash-completion/completions/` +* Copy :file:`west-completion.bash` to a local folder and source it from your :file:`~/.bashrc` + +On macOS you have the following options: + +* Copy :file:`west-completion.bash` to a local folder and source it from your + :file:`~/.bash_profile` +* Install the ``bash-completion`` package with ``brew``:: + + brew install bash-completion + + then source the main bash completion script in your :file:`~/.bash_profile`:: + + source /usr/local/etc/profile.d/bash_completion.sh + + and finally copy :file:`west-completion.bash` to + :file:`/usr/local/etc/bash_completion.d/` + + +.. _PyPI: + https://pypi.org/project/west/ + From 928f17cfa4255fc7fcf31f004279c8faf20abc52 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 12 May 2019 01:05:43 -0600 Subject: [PATCH 035/226] doc: updates for west installation docs Grammar and formatting improvements, as well as changes requested in review that weren't made (in particular, the ones recommending using "pip3 show -f west" to see where west is installed instead of listing common places that might not be right. Signed-off-by: Marti Bolivar --- doc/guides/west/install.rst | 50 ++++++++++++------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/doc/guides/west/install.rst b/doc/guides/west/install.rst index 0b2d30b6..e9b4a1e0 100644 --- a/doc/guides/west/install.rst +++ b/doc/guides/west/install.rst @@ -15,32 +15,13 @@ On Windows and macOS:: pip3 install -U west .. note:: - See :ref:`gs_python_deps` for additional clarfication on using the + See :ref:`gs_python_deps` for additional clarification on using the ``--user`` switch. -The following are the typical locations where the west files will be -installed if you followed the instructions above: +Afterwards, you can run ``pip3 show -f west`` for information on where the west +binary and related files were installed. -.. tip:: - You can use the ``pip3 show -f west`` command to display information about - the installed packaged, including file locations. - -* Linux: - - * Executable: :file:`~/.local/bin/west` - * Package: :file:`~/.local/lib/python3./site-packages/west/` - -* macOS: - - * Executable: :file:`/usr/local/bin/west` - * Package: :file:`/usr/local/lib/python3./site-packages/west/` - -* Windows: - - * Executable: :file:`C:\\Python3\\Scripts\\west.exe` - * Package: :file:`C:\\Python3\\Lib\\site-packages\\west\\` - -Once west is installed you can use it to :ref:`clone the Zephyr repositories +Once west is installed, you can use it to :ref:`clone the Zephyr repositories `. .. _west-shell-completion: @@ -64,18 +45,21 @@ To obtain the completion script you can use the ``west completion`` command:: west completion bash > west-completion.bash .. note:: - Remember to update the completion script using ``west completion`` regularly - to always have an up to date copy of it. -Next you need to have it sourced. + Remember to update your local copy of the completion script using ``west + completion`` when you update Zephyr. + +Next, you need to import :file:`west-completion.bash` into your bash shell. -On Linux you have the following options: +On Linux, you have the following options: -* Copy :file:`west-completion.bash` to :file:`/etc/bash_completion.d/` -* Copy :file:`west-completion.bash` to :file:`/usr/share/bash-completion/completions/` -* Copy :file:`west-completion.bash` to a local folder and source it from your :file:`~/.bashrc` +* Copy :file:`west-completion.bash` to :file:`/etc/bash_completion.d/`. +* Copy :file:`west-completion.bash` to + :file:`/usr/share/bash-completion/completions/`. +* Copy :file:`west-completion.bash` to a local folder and source it from your + :file:`~/.bashrc`. -On macOS you have the following options: +On macOS, you have the following options: * Copy :file:`west-completion.bash` to a local folder and source it from your :file:`~/.bash_profile` @@ -88,9 +72,7 @@ On macOS you have the following options: source /usr/local/etc/profile.d/bash_completion.sh and finally copy :file:`west-completion.bash` to - :file:`/usr/local/etc/bash_completion.d/` - + :file:`/usr/local/etc/bash_completion.d/`. .. _PyPI: https://pypi.org/project/west/ - From 651f97dc93af7d293b52bd4e32fcb380f7a1de40 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 12 May 2019 01:52:26 -0600 Subject: [PATCH 036/226] doc: updates to west multi-repo docs Minor updates. Signed-off-by: Marti Bolivar --- doc/guides/west/repo-tool.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 20a44976..9f1217e4 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -3,7 +3,7 @@ Multiple Repository Management ############################## -This page introduces basic concepts related to West and its multiple repository +This page introduces basic concepts related to west and its multiple repository management features, and gives an overview of the associated commands. See :ref:`west-history` and `Zephyr issue #6770`_ for additional discussion, rationale, and motivation. @@ -173,14 +173,14 @@ functionality. Some commands loosely mimic the corresponding Git command, but in a multi-repo context (e.g. ``west diff`` shows local changes on all repositories). -Project arguments can be the names of projects in the manifest, or their paths -within the installation. Passing no project arguments to commands that accept a -list of projects usually means to use all projects in the manifest. +Project arguments can be the names of projects in the manifest, or (as +fallback) paths to them. Omitting project arguments to commands which accept a +list of projects (such as ``west list``, ``west forall``, etc.) usually +defaults to using all projects in the manifest file plus the manifest +repository itself. -.. note:: - - For detailed help, see each command's ``--help`` output (e.g. ``west diff - --help``). +For help on individual commands, run ``west -h`` (e.g. ``west diff +-h``). Main Commands ============= @@ -206,10 +206,10 @@ important to understand. https://github.com/zephyrproject-rtos/zephyr --mr v1.15.0`` would clone the upstream official zephyr repository at the tagged release v1.15.0 (``-m`` defaults to https://github.com/zephyrproject-rtos/zephyr, and - ``--mr`` defaults to ``master``). + the ``-mr`` default is overridden to ``v1.15.0``). - ``west update [--rebase] [--keep-descendants] [--exclude-west] [PROJECT - ...]``: clone and update the specified projects (default: all projects) based + ...]``: clone and update the specified projects based on the current :term:`west manifest`. This command parses the manifest, clones any project repositories that are From 001027e834f1c0971b41ad481ed30873eb9ada29 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 12 May 2019 01:52:42 -0600 Subject: [PATCH 037/226] doc: move sign command docs before catch-all page The current order makes no sense. Move it earlier in the order, so the catch-all page appears last. Signed-off-by: Marti Bolivar --- doc/guides/west/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index eabbc0c3..7bbad616 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -39,8 +39,8 @@ context about the tool. config.rst extensions.rst build-flash-debug.rst - zephyr-cmds.rst sign.rst + zephyr-cmds.rst why.rst without-west.rst planned.rst From aa680ab302c2a7a314c5fafc7e8d9ce4669433f5 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 10 May 2019 10:27:59 -0400 Subject: [PATCH 038/226] doc: move module related doc to guides Move to a new guide which will expand on how to submit modules and how to maintain them. Also move topology documentation to repository management section where it fits better. Signed-off-by: Anas Nashif --- doc/guides/west/repo-tool.rst | 68 ++++++++++++++++++++++++++++++++ doc/guides/west/why.rst | 67 ------------------------------- doc/guides/west/without-west.rst | 2 +- 3 files changed, 69 insertions(+), 68 deletions(-) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 9f1217e4..bd5d0be7 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -79,6 +79,74 @@ Finally, any repository managed by a west installation can contain provided by that project. This includes the manifest repository and any project repository. +Topologies supported +******************** + +The following three source code topologies supported by west: + +* **T1**: Star topology with zephyr as the manifest repository: + + - The zephyr repository acts as the central repository and includes a + complete list of projects used upstream + - Default (upstream) configuration + - Analogy with existing mechanisms: Git sub-modules with zephyr as the + super-project + - See :ref:`west-installation` for how mainline Zephyr is an example + of this topology + +* **T2**: Star topology with an application repository as the manifest + repository: + + - A repository containing a Zephyr application acts as the central repository + and includes a complete list of other projects, including the zephyr + repository, required to build it + - Useful for those focused on a single application + - Analogy with existing mechanisms: Git sub-modules with the application as + the super-project, zephyr and other projects as sub-modules + - An installation using this topology could look like this: + + .. code-block:: none + + app-manifest-installation + ├── application + │   ├── CMakeLists.txt + │   ├── prj.conf + │   ├── src + │   │   └── main.c + │   └── west.yml + ├── modules + │   └── lib + │   └── tinycbor + └── zephyr + +* **T3**: Forest topology: + + - A dedicated manifest repository which contains no Zephyr source code, + and specifies a list of projects all at the same "level" + - Useful for downstream distributions with no "central" repository + - Analogy with existing mechanisms: Google repo-based source distribution + - An installation using this topology could look like this: + + .. code-block:: none + + forest + ├── app1 + │   ├── CMakeLists.txt + │   ├── prj.conf + │   └── src + │   └── main.c + ├── app2 + │   ├── CMakeLists.txt + │   ├── prj.conf + │   └── src + │   └── main.c + ├── manifest-repo + │   └── west.yml + ├── modules + │   └── lib + │   └── tinycbor + └── zephyr + .. _west-struct: West Structure diff --git a/doc/guides/west/why.rst b/doc/guides/west/why.rst index ea63135a..e690b757 100644 --- a/doc/guides/west/why.rst +++ b/doc/guides/west/why.rst @@ -32,73 +32,6 @@ The basic requirements are: * **R4**: Support both continuous tracking and commit-based (bisectable) project updating -Topologies supported -******************** - -The requirements above lead to three source code topologies supported by west: - -* **T1**: Star topology with zephyr as the manifest repository: - - - The zephyr repository acts as the central repository and includes a - complete list of projects used upstream - - Default (upstream) configuration - - Analogy with existing mechanisms: Git submodules with zephyr as the - superproject - - See :ref:`west-installation` for how mainline Zephyr is an example - of this topology - -* **T2**: Star topology with an application repository as the manifest - repository: - - - A repository containing a Zephyr application acts as the central repository - and includes a complete list of other projects, including the zephyr - repository, required to build it - - Useful for those focused on a single application - - Analogy with existing mechanisms: Git submodules with the application as - the superproject, zephyr and other projects as submodules - - An installation using this topology could look like this: - - .. code-block:: none - - app-manifest-installation - ├── application - │   ├── CMakeLists.txt - │   ├── prj.conf - │   ├── src - │   │   └── main.c - │   └── west.yml - ├── modules - │   └── lib - │   └── tinycbor - └── zephyr - -* **T3**: Forest topology: - - - A dedicated manifest repository which contains no Zephyr source code, - and specifies a list of projects all at the same "level" - - Useful for downstream distributions with no "central" repository - - Analogy with existing mechanisms: Google repo-based source distribution - - An installation using this topology could look like this: - - .. code-block:: none - - forest - ├── app1 - │   ├── CMakeLists.txt - │   ├── prj.conf - │   └── src - │   └── main.c - ├── app2 - │   ├── CMakeLists.txt - │   ├── prj.conf - │   └── src - │   └── main.c - ├── manifest-repo - │   └── west.yml - ├── modules - │   └── lib - │   └── tinycbor - └── zephyr Rationale for a custom tool *************************** diff --git a/doc/guides/west/without-west.rst b/doc/guides/west/without-west.rst index 23d8095c..467f532f 100644 --- a/doc/guides/west/without-west.rst +++ b/doc/guides/west/without-west.rst @@ -56,7 +56,7 @@ repositories, the build will still work. If you don't have west installed and your application *does* need one of these repositories, you must set :makevar:`ZEPHYR_MODULES` -yourself. See :ref:`ext-projs` for details. +yourself. See :ref:`modules` for details. Flashing and Debugging ---------------------- From 6745196d99e6fdcdbc6aa4908f21c6f70d03cc08 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Wed, 5 Jun 2019 16:04:29 +0200 Subject: [PATCH 039/226] west: build: Configurable build folder format Add the possibility of configuring the build folder format in west's configuration system. The build.dir-fmt configuration option controls how west will create build folders when not specified, the following parameters are currently accepted: - board: The board name - source_dir: The relative path from CWD to the source directory - app: The name of the source directory If CWD is below source_dir in the directory hierarchy then source_dir is set to an empty string. This means that if one sets: [build] dir-fmt = build/{board}/{source_dir} Then when building samples/hello_world from zephyr's root for the reel_board the build folder will be: ./build/reel_board/samples/hello_world but when building it from inside the samples/hello_world folder it will instead be: ./build/reel_board Fixes https://github.com/zephyrproject-rtos/west/issues/124 Signed-off-by: Carles Cufi Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 88 +++++++++++++++++++-------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 724a1137..0a256006 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -32,19 +32,15 @@ Building: ``west build`` The ``build`` command helps you build Zephyr applications from source. You can use :ref:`west config ` to configure its behavior. -This command attempts to "do what you mean" when run from a Zephyr application -source or build directory: +Its default behavior tries to "do what you mean": -- When you run ``west build`` in an existing build directory, the board, source - directory, etc. are obtained from the CMake cache, and that build directory - is re-compiled. +- If there is a Zephyr build directory named :file:`build` in your current + working directory, it is incrementally re-compiled. The same is true if you + run ``west build`` from a Zephyr build directory. -- The same is true if a Zephyr build directory named :file:`build` exists in - your current working directory. - -- Otherwise, the source directory defaults to the current working directory, so - running ``west build`` from a Zephyr application's source directory compiles - it. +- Otherwise, if you run ``west build`` from a Zephyr application's source + directory and no build directory is found, a new one is created and the + application is compiled in it. Basics ====== @@ -66,15 +62,23 @@ exactly the same name you would supply to CMake if you were to invoke it with: A build directory named :file:`build` will be created, and the application will be compiled there after ``west build`` runs CMake to create a build system in -that directory. If you run ``west build`` with an existing build directory, the -application is incrementally re-compiled without re-running CMake (you can -force CMake to run again with ``--cmake``). +that directory. If ``west build`` finds an existing build directory, the +application is incrementally re-compiled there without re-running CMake. You +can force CMake to run again with ``--cmake``. You don't need to use the ``--board`` option if you've already got an existing build directory; ``west build`` can figure out the board from the CMake cache. For new builds, the ``--board`` option, :envvar:`BOARD` environment variable, or ``build.board`` configuration option are checked (in that order). +Examples +======== + +Here are some ``west build`` usage examples, grouped by area. + +Setting a Default Board +----------------------- + To configure ``west build`` to build for the ``reel_board`` by default:: west config build.board reel_board @@ -82,15 +86,36 @@ To configure ``west build`` to build for the ``reel_board`` by default:: (You can use any other board supported by Zephyr here; it doesn't have to be ``reel_board``.) -To use another build directory, use ``--build-dir`` (or ``-d``):: +.. _west-building-dirs: - west build -b --build-dir path/to/build/directory +Setting Source and Build Directories +------------------------------------ -To specify the application source directory explicitly, give its path as a +To set the application source directory explicitly, give its path as a positional argument:: west build -b path/to/source/directory +To set the build directory explicitly, use ``--build-dir`` (or ``-d``):: + + west build -b --build-dir path/to/build/directory + +To change the default build directory from :file:`build`, use the +``build.dir-fmt`` configuration option. This lets you name build +directories using format strings, like this:: + + west config build.dir-fmt "build/{board}/{app}" + +With the above, running ``west build -b reel_board samples/hello_world`` will +use build directory :file:`build/reel_board/hello_world`. See +:ref:`west-building-config` for more details on this option. + +Controlling the Build System +---------------------------- + +There are several ways to control the build system generated and used by ``west +build``. + To specify the build system target to run, use ``--target`` (or ``-t``). For example, on host platforms with QEMU, you can use the ``run`` target to @@ -125,7 +150,6 @@ To let west decide for you if a pristine build is needed, use ``-p auto``:: You can run ``west config build.pristine auto`` to make this setting permanent. - .. _west-building-generator: To add additional arguments to the CMake invocation performed by ``west @@ -159,6 +183,8 @@ To force a CMake re-run, use the ``--cmake`` (or ``--c``) option:: west build -c +.. _west-building-config: + Configuration Options ===================== @@ -179,6 +205,16 @@ You can :ref:`configure ` ``west build`` using these options. * - ``build.board_warn`` - Boolean, default ``true``. If ``false``, disables warnings when ``west build`` can't figure out the target board. + * - ``build.dir-fmt`` + - String, default ``build``. The build folder format string, used by + west whenever it needs to create or locate a build folder. The currently + available arguments are: + + - ``board``: The board name + - ``source_dir``: The relative path from the current working directory + to the source directory. If the current working directory is inside + the source directory this will be set to an empty string. + - ``app``: The name of the source directory. * - ``build.generator`` - String, default ``Ninja``. The `CMake Generator`_ to use to create a build system. (To set a generator for a single build, see the @@ -219,10 +255,10 @@ To specify the build directory, use ``--build-dir`` (or ``-d``):: west flash --build-dir path/to/build/directory -Since the build directory defaults to :file:`build`, if you do not specify -a build directory but a folder named :file:`build` is present, that will be -used, allowing you to flash from outside the :file:`build` folder with no -additional parameters. +If you don't specify the build directory, ``west flash`` searches for one in +:file:`build`, then the current working directory. If you set the +``build.dir-fmt`` configuration option (see :ref:`west-building-dirs`), ``west +flash`` searches there instead of :file:`build`. Choosing a Runner ================= @@ -315,10 +351,10 @@ To specify the build directory, use ``--build-dir`` (or ``-d``):: west debug --build-dir path/to/build/directory west debugserver --build-dir path/to/build/directory -Since the build directory defaults to :file:`build`, if you do not specify -a build directory but a folder named :file:`build` is present, that will be -used, allowing you to debug from outside the :file:`build` folder with no -additional parameters. +If you don't specify the build directory, these commands search for one in +:file:`build`, then the current working directory. If you set the +``build.dir-fmt`` configuration option (see :ref:`west-building-dirs`), ``west +debug`` searches there instead of :file:`build`. Choosing a Runner ================= From 78111cb5bcc691bd59f897d3c89642ad403c9a4f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 13 Jun 2019 09:11:52 -0600 Subject: [PATCH 040/226] docs: update west sign docs Updates for recent changes. Signed-off-by: Marti Bolivar --- doc/guides/west/sign.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/sign.rst b/doc/guides/west/sign.rst index d381e8d4..5fe5828e 100644 --- a/doc/guides/west/sign.rst +++ b/doc/guides/west/sign.rst @@ -35,8 +35,13 @@ Some additional notes follow. See ``west sign -h`` for detailed help. - If you don't have your own signing key and have a default MCUboot build, use ``--key path/to/mcuboot/root-rsa-2048.pem``. - By default, the output files produced by ``west sign`` are named - :file:`zephyr.signed.bin` and :file:`zephyr.signed.hex`. You can control this - using the ``-B`` and ``-H`` options, e.g.: + :file:`zephyr.signed.bin` and :file:`zephyr.signed.hex` and are created in the + build directory next to the unsigned :file:`zephyr.bin` and :file:`zephyr.hex` + versions. + + You can control this using the ``-B`` and ``-H`` options, e.g. this would + create :file:`my-signed.bin` and :file:`my-signed.hex` in the current working + directory instead: .. code-block:: console @@ -44,6 +49,7 @@ Some additional notes follow. See ``west sign -h`` for detailed help. Example build flow ****************** + For reference, here is an example showing how to build :ref:`hello_world` for MCUboot using ``west``: @@ -51,9 +57,11 @@ MCUboot using ``west``: west build -b YOUR_BOARD samples/hello_world -- -DCONFIG_BOOTLOADER_MCUBOOT=y west sign -t imgtool -- --key YOUR_SIGNING_KEY.pem - west flash --hex-file zephyr.signed.hex + west flash --hex-file build/zephyr/zephyr.signed.hex -Availability of a hex file depends on your build configuration. +The availability of a hex file, and whether ``west flash`` uses it to flash, +depends on your board and build configuration. At least the west flash runners +using ``nrfjprog`` and ``pyocd`` work with the above flow. .. _MCUboot: https://mcuboot.com/ From 9fc2d631b03a379c1f2c6a6c2a84a9db8243aec0 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 17 Jun 2019 11:47:11 +0200 Subject: [PATCH 041/226] west: runners: Guess build folder When using a build folder format with build.dir-fmt that includes any parameters that need resolving, the west runners cannot find the folder since the required information (board, source dir or app) is not available. Add a very simple heuristic to support the case where a build folder starts with a hardcoded prefix (for example 'build/') and a single build is present under that prefix. The heuristic is gated behind a new configuration option: build.guess-dir Signed-off-by: Carles Cufi --- doc/guides/west/build-flash-debug.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 0a256006..655a3644 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -219,6 +219,16 @@ You can :ref:`configure ` ``west build`` using these options. - String, default ``Ninja``. The `CMake Generator`_ to use to create a build system. (To set a generator for a single build, see the :ref:`above example `) + * - ``build.guess-dir`` + - String, instructs west whether to try to guess what build folder to use + when ``build.dir-fmt`` is in use and not enough information is available + to resolve the build folder name. Can take these values: + + - ``never`` (default): Never try to guess, bail out instead and + require the user to provide a build folder with ``-d``. + - ``runners``: Try to guess the folder when using any of the 'runner' + commands. These are typically all commands that invoke an external + tool, such as ``flash`` and ``debug``. * - ``build.pristine`` - String. Controls the way in which ``west build`` may clean the build folder before building. Can take the following values: From 909042db73720cc44375e938c0806ba1c86982a9 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 25 Jul 2019 20:43:13 +0200 Subject: [PATCH 042/226] doc: Consolidate Python and pip documentation The documentation that describes how Python and pip interact with the OS when installing packages used to be under a common section, and was moved to the west bootstrap one later on. Since this information is required early on (for example on Linux when installing CMake via pip3), move the info to its own section and link to it from others. Signed-off-by: Carles Cufi --- doc/guides/west/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/west/install.rst b/doc/guides/west/install.rst index e9b4a1e0..523fb852 100644 --- a/doc/guides/west/install.rst +++ b/doc/guides/west/install.rst @@ -15,7 +15,7 @@ On Windows and macOS:: pip3 install -U west .. note:: - See :ref:`gs_python_deps` for additional clarification on using the + See :ref:`python-pip` for additional clarification on using the ``--user`` switch. Afterwards, you can run ``pip3 show -f west`` for information on where the west From 978be2757db34b9b915f6861eb38cdd4cfe9d47e Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 13 Jun 2019 14:16:32 -0600 Subject: [PATCH 043/226] doc: add a release notes page for west This just documents what's already happened. A subsequent patch will extend it for v0.6.x. Signed-off-by: Marti Bolivar --- doc/guides/west/index.rst | 1 + doc/guides/west/release-notes.rst | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 doc/guides/west/release-notes.rst diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 7bbad616..00dd8877 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -44,6 +44,7 @@ context about the tool. why.rst without-west.rst planned.rst + release-notes.rst For details on west's Python APIs (including APIs provided by extensions in the zephyr), see :ref:`west-apis`. diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst new file mode 100644 index 00000000..c72dbf43 --- /dev/null +++ b/doc/guides/west/release-notes.rst @@ -0,0 +1,25 @@ +West Release Notes +################## + +v0.5.x +****** + +West v0.5.x is the first version used widely by the Zephyr Project as part of +its v1.14 Long-Term Support (LTS) release. The `west v0.5.x documentation`_ is +available as part of the Zephyr's v1.14 documentation. + +West's main features in v0.5.x are: + +- Multiple repository management using Git repositories, including self-update + of west itself +- Hierarchical configuration files +- Extension commands + +Versions Before v0.5.x +********************** + +Tags in the west repository before v0.5.x are prototypes which are of +historical interest only. + +.. _west v0.5.x documentation: + https://docs.zephyrproject.org/1.14.0/guides/west/index.html From 5a755fe21c8431576bc0c499e772f23c53f39f04 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 22 Jul 2019 11:00:22 -0600 Subject: [PATCH 044/226] doc: move runner documentation out of west-apis.rst Now that the runners package no longer depends on west, we can move the documentation for it from the orphan west-apis.rst page to the build-flash-debug.rst page that documents the west extension commands which use that package. (This is a more logical place for this information, but it was previously not possible to put it there since we must be able to build the documentation on a system without west installed, excepting content in west-apis.rst. Removing the dependency means the runners automodule directive can safely appear in build-flash-debug.rst.) Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 25 +++++++++++++++++-------- doc/guides/west/index.rst | 3 +-- doc/guides/west/west-apis.rst | 19 ------------------- doc/guides/west/west-not-found.rst | 1 - 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 655a3644..c3cd2d23 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -463,13 +463,22 @@ determined by the imported subclasses of ``ZephyrBinaryRunner``. individual runner implementations are in other submodules, such as ``runners.nrfjprog``, ``runners.openocd``, etc. -Hacking and APIs -**************** +Hacking +******* + +This section contains documentation the ``runners.core`` module used by the +flash and debug commands. This is the core abstraction used to implement +support for these features. + +.. warning:: + + These APIs are provided for reference, but they are more "shared code" used + to implement multiple extension commands than a stable API. -Developers can add support for new ways to flash and debug Zephyr -programs by implementing additional runners. To get this support into -upstream Zephyr, the runner should be added into a new or existing -``runners`` module, and imported from :file:`runner/__init__.py`. +Developers can add support for new ways to flash and debug Zephyr programs by +implementing additional runners. To get this support into upstream Zephyr, the +runner should be added into a new or existing ``runners`` module, and imported +from :file:`runners/__init__.py`. .. note:: @@ -480,8 +489,8 @@ upstream Zephyr, the runner should be added into a new or existing changes break existing test cases, CI testing on upstream pull requests will fail. -API Documentation for the ``runners.core`` module can be found in -:ref:`west-apis`. +.. automodule:: runners.core + :members: Doing it By Hand **************** diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 00dd8877..48a38510 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -46,8 +46,7 @@ context about the tool. planned.rst release-notes.rst -For details on west's Python APIs (including APIs provided by extensions in the -zephyr), see :ref:`west-apis`. +For details on west's Python APIs, see :ref:`west-apis`. .. rubric:: Footnotes diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 1b2ed5a4..24113ee2 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -72,24 +72,5 @@ west.util .. automodule:: west.util :members: west_dir, west_topdir, WestNotFound -.. _west-apis-zext: - -Zephyr Extensions -***************** - -This section contains documentation for APIs used by the extension commands -which are part of the Zephyr repository. In particular, it documents the -``runners.core`` module used by the :ref:`west-build-flash-debug` -commands. This is the core abstraction used to implement support for these -features. - -.. warning:: - - These APIs are provided for reference, but they are more "shared code" used - to implement multiple extension commands than a stable API. - -.. automodule:: runners.core - :members: - .. _west #38: https://github.com/zephyrproject-rtos/west/issues/38 diff --git a/doc/guides/west/west-not-found.rst b/doc/guides/west/west-not-found.rst index a584f6bf..d54c3b4f 100644 --- a/doc/guides/west/west-not-found.rst +++ b/doc/guides/west/west-not-found.rst @@ -7,7 +7,6 @@ .. _west-apis-log: .. _west-apis-manifest: .. _west-apis-util: -.. _west-apis-zext: West APIs ######### From 43eed314ade0e768b220932d4623761dfdf24a55 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 22 Jul 2019 11:00:59 -0600 Subject: [PATCH 045/226] west: require v0.6.0 or higher The main change is the elimination of the bootstrapper, a design flaw / misfeature. Update the documentation to be compatible with the 0.6.x releases as well. This has to be done atomically, as there were incompatible changes. Make use of the versionchanged and versionadded directives to begin keeping track of how these APIs are evolving. (Note that west 0.6.0 will remain compatible with the extension commands in Zephyr v1.14 LTS as long as that is still alive. This change is targeted towards Zephyr 2.0 users.) This requires a bump in the shippable container and allows us to simplify the west_commands test procedure. Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 2 +- doc/guides/west/index.rst | 2 +- doc/guides/west/manifest.rst | 5 + doc/guides/west/release-notes.rst | 95 +++++++++++++ doc/guides/west/repo-tool.rst | 83 ++---------- doc/guides/west/west-apis.rst | 183 ++++++++++++++++++++++---- 6 files changed, 274 insertions(+), 96 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index c3cd2d23..3599f1f9 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -466,7 +466,7 @@ individual runner implementations are in other submodules, such as Hacking ******* -This section contains documentation the ``runners.core`` module used by the +This section documents the ``runners.core`` module used by the flash and debug commands. This is the core abstraction used to implement support for these features. diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 48a38510..4f27fd14 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -27,7 +27,7 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.5.x`` releases, and provide additional +The following pages document west's ``v0.6.x`` releases, and provide additional context about the tool. .. toctree:: diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 5a4b14ea..59d15e43 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -206,6 +206,11 @@ described next. - ``remote``: The name of the project's remote. If not given, the ``remote`` value in the ``defaults`` subsection is tried next. If both are missing, the manifest is invalid. +- ``repo-path``: Optional. If given, this is concatenated on to the remote's + ``url-base`` instead of the project's ``name`` to form its fetch URL. +- ``url``: Optional. If given, this is the project's complete fetch URL. + It cannot be combined with either ``remote`` or ``repo-path``. Note that this + overrides any default remote. - ``revision``: Optional. The current project revision used by ``west update``. If not given, the value from the ``defaults`` subsection will be used if present. If both are missing, ``master`` is used. A project revision can be diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index c72dbf43..cb4ebc7e 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,6 +1,97 @@ West Release Notes ################## +v0.6.x +****** + +- No separate bootstrapper + + In west v0.5.x, the program was split into two components, a bootstrapper and + a per-installation clone. See `Multiple Repository Management in the v1.14 + documentation`_ for more details. + + This is similar to how Google's Repo tool works, and lets west iterate quickly + at first. It caused confusion, however, and west is now stable enough to be + distributed entirely as one piece via PyPI. + + From v0.6.x onwards, all of the core west commands and helper classes are + part of the west package distributed via PyPI. This eliminates complexity + and makes it possible to import west modules from anywhere in the system, + not just extension commands. +- The ``selfupdate`` command still exists for backwards compatibility, but + now simply exits after printing an error message. +- Manifest syntax changes + + - A west manifest file's ``projects`` elements can now specify their fetch + URLs directly, like so: + + .. code-block:: yaml + + manifest: + projects: + - name: example-project-name + url: https://github.com/example/example-project + + Project elements with ``url`` attributes set in this way may not also have + ``remote`` attributes. + - Project names must be unique: this restriction is needed to support future + work, but was not possible in west v0.5.x because distinct projects may + have URLs with the same final pathname component, like so: + + .. code-block:: yaml + + manifest: + remotes: + - name: remote-1 + url-base: https://github.com/remote-1 + - name: remote-2 + url-base: https://github.com/remote-2 + projects: + - name: project + remote: remote-1 + path: remote-1-project + - name: project + remote: remote-2 + path: remote-2-project + + These manifests can now be written with projects that use ``url`` + instead of ``remote``, like so: + + .. code-block:: yaml + + manifest: + projects: + - name: remote-1-project + url: https://github.com/remote-1/project + - name: remote-2-project + url: https://github.com/remote-2/project + +- The ``west list`` command now supports a ``{sha}`` format string key + +- The default format string for ``west list`` was changed to ``"{name:12} + {path:28} {revision:40} {url}"``. + +- The command ``west manifest --validate`` can now be run to load and validate + the current manifest file, among other error-handling fixes related to + manifest parsing. + +- Incompatible API changes were made to west's APIs. Further changes are + expected until API stability is declared in west v1.0. + + - The ``west.manifest.Project`` constructor's ``remote`` and ``defaults`` + positional arguments are now kwargs. A new ``url`` kwarg was also added; if + given, the ``Project`` URL is set to that value, and the ``remote`` kwarg + is ignored. + + - ``west.manifest.MANIFEST_SECTIONS`` was removed. There is only one section + now, namely ``manifest``. The *sections* kwargs in the + ``west.manifest.Manifest`` factory methods and constructor were also + removed. + + - The ``west.manifest.SpecialProject`` class was removed. Use + ``west.manifest.ManifestProject`` instead. + + v0.5.x ****** @@ -21,5 +112,9 @@ Versions Before v0.5.x Tags in the west repository before v0.5.x are prototypes which are of historical interest only. +.. _Multiple Repository Management in the v1.14 documentation: + https://docs.zephyrproject.org/1.14.0/guides/west/repo-tool.html + .. _west v0.5.x documentation: https://docs.zephyrproject.org/1.14.0/guides/west/index.html + diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index bd5d0be7..e5350133 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -26,16 +26,14 @@ Git repositories installed under a common parent directory, which we call a `_. A west installation is the result of running the ``west init`` command, which -is described in more detail below. This command can either create a new -installation, or convert a standalone "mono-repo" zephyr repository into a full -west installation. For upstream Zephyr, the installation looks like this: +is described in more detail below. For upstream Zephyr, the installation looks +like this: .. code-block:: none zephyrproject ├── .west - │ ├── config - │ └── west + │ └── config ├── zephyr │ ├── west.yml │ └── [... other files ...] @@ -48,9 +46,7 @@ west installation. For upstream Zephyr, the installation looks like this: Above, :file:`zephyrproject` is the name of the west installation's root directory. This name is just an example -- it could be anything, like ``z``, ``my-zephyr-installation``, etc. The file :file:`.west/config` is the -installation's :ref:`local configuration file `. The directory -:file:`.west/west` is a clone of the west repository itself; more details on -why that is currently needed are given in the next section. +installation's :ref:`local configuration file `. Every west installation contains exactly one *manifest repository*, which is a Git repository containing a file named :file:`west.yml`, which is the *west @@ -152,62 +148,12 @@ The following three source code topologies supported by west: West Structure ************** -West is currently split in two: +West's code is distributed via PyPI in a `namespace package`_ named ``west``. +See :ref:`west-apis` for API documentation. -* Bootstrapper: Installed by ``pip3 install west``, which provides the ``west`` - binary and the ``west init`` command. -* Per-installation clone: this is the west repository cloned into each - installation, which provides the built-in commands. - -.. note:: - - This "bootstrapper" / "everything else" separation is similar to the model - used by Google's ``repo`` tool, but unfortunately in retrospect was not a - good strategy for west. - - In future versions, the ``west`` binary and all built-in commands (including - ``init``) will be installed by ``pip3 install west``. Besides eliminating - complexity, this will also make it possible to use :ref:`West's APIs - ` from any Python file, not just extension - commands. - - Updating west will still be possible manually, e.g. with ``pip3 - install --upgrade west``. If necessary, it will also still be possible to - use different versions of west on the same computer through Python virtual - environments. - -Bootstrapper -============ - -The bootstrapper module is distributed using `PyPI`_ and installed using -:file:`pip3`. A launcher named ``west`` is placed by :file:`pip3` in the user's -``PATH``. This the only entry point to west. It implements a single command: -``west init``. This command needs to be run first to use the rest of -functionality included in ``west``, by creating a west installation. The -command ``west init`` does the following: - -* Clones west itself in a :file:`.west/west` folder in the installation. -* Clones the manifest repository in the folder specified by the manifest file's - ``self.path`` section. -* Creates an initial local configuration file. - -Once ``west init`` has been run, the bootstrapper will delegate the handling of -any west commands other than ``init`` to the cloned west repository. This means -that there is a single bootstrapper instance installed at any time (unless you -use virtual environments), which can then be used to initialize as many -installations as needed, each of which can have a different version of west. - -.. _west-struct-installation: - -Per-Installation Clone -====================== - -A west installation, as described above, contains a clone of the west -repository in :file:`.west/west`. This is where the built-in command -implementations are currently provided. The rest of :ref:`West's APIs -` are also currently provided to extension commands by this -repository. So that west can update itself, the built-in ``west update`` and -``west selfupdate`` commands fetch and update the :file:`.west/west` repository. +This distribution also includes a launcher executable, also named ``west``. When +west is installed, the launcher is placed by :file:`pip3` somewhere in the +user's ``PATH``. This is the command-line entry point. The ``manifest-rev`` branch *************************** @@ -266,7 +212,8 @@ important to understand. 1. If you already have a local clone of the zephyr repository and want to create a west installation around it, you can use the ``-l`` switch to - pass its path to west, as in: ``west init -l path/to/zephyr``. + pass its path to west, as in: ``west init -l path/to/zephyr``. This is + the only reason to use ``-l``. 2. Otherwise, omit ``-l`` to create a new installation from a remote manifest repository. You can give the manifest URL using the ``-m`` switch, and its @@ -291,9 +238,6 @@ important to understand. the ``--rebase`` / ``-r`` and ``--keep-descendants`` / ``-k`` options for ways to influence this. - By default, ``west update`` also updates the west repository in the - installation. To prevent this, use ``--exclude-west``. - .. _west-multi-repo-misc: Miscellaneous Commands @@ -324,10 +268,11 @@ discussed here. forall -c 'git --options'``. Note that ``west forall`` can be used to run any command, though, not just Git commands. -- ``west selfupdate``: Updates the west repository in the installation. - .. _PyPI: https://pypi.org/project/west/ .. _Zephyr issue #6770: https://github.com/zephyrproject-rtos/zephyr/issues/6770 + +.. _namespace package: + https://www.python.org/dev/peps/pep-0420/ diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 24113ee2..070f9892 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -1,31 +1,25 @@ :orphan: .. _west-apis: +.. _west-apis-west: -West and Extension APIs -####################### +West APIs +######### This page documents the Python APIs provided by :ref:`west `, as well as some additional APIs used by the :ref:`west extensions ` in the zephyr repository. -**Contents**: - -.. contents:: - :local: - -.. _west-apis-west: +.. warning:: -West -**** + These APIs should be considered unstable until west version 1.0 (see `west + #38`_). -This section contains documentation for west's APIs. -.. warning:: +**Contents**: - These APIs should be considered unstable until west version 1.0. Further, - until `west #38`_ is closed, these modules can only be imported from - extension command files (and within west itself, of course). +.. contents:: + :local: .. NOTE: documentation authors: @@ -35,23 +29,111 @@ This section contains documentation for west's APIs. .. _west-apis-commands: west.commands -============= +************* + +.. module:: west.commands + +All built-in and extension commands are implemented as subclasses of the +:py:class:`WestCommand` class defined here. Some exception types are also +provided. + +.. py:class:: west.commands.WestCommand + + .. automethod:: __init__ + + .. versionadded:: 0.6 + The *requires_installation* parameter. + + Methods: + + .. automethod:: run + + .. versionchanged:: 0.6 + The *topdir* argument was added. + + .. automethod:: add_parser + + All subclasses must provide the following abstract methods, which are used + to implement the above: + + .. automethod:: do_add_parser + + .. automethod:: do_run + + Instance attributes: + + .. py:attribute:: name + + As passed to the constructor. + + .. py:attribute:: help + + As passed to the constructor. + + .. py:attribute:: description + + As passed to the constructor. + + .. py:attribute:: accepts_unknown_args + + As passed to the constructor. + + .. py:attribute:: requires_installation + + As passed to the constructor. + + .. py:attribute:: parser -.. automodule:: west.commands - :members: WestCommand, CommandError, CommandContextError, ExtensionCommandError + The argument parser created by calling ``WestCommand.add_parser()``. + +.. autoclass:: west.commands.CommandError + :show-inheritance: + + .. py:attribute:: returncode + + Recommended program exit code for this error. + +.. autoclass:: west.commands.CommandContextError + :show-inheritance: + +.. autoclass:: west.commands.ExtensionCommandError + :show-inheritance: + + .. py:method:: ExtensionCommandError.__init__(hint=None, **kwargs) + + If *hint* is given, it is a string indicating the cause of the problem. + All other kwargs are passed to the super constructor. + + .. py:attribute:: hint + + As passed to the constructor. .. _west-apis-configuration: west.configuration -================== +****************** .. automodule:: west.configuration - :members: ConfigFile, read_config, update_config + +.. autoclass:: west.configuration.ConfigFile + +.. autofunction:: west.configuration.read_config + +.. versionchanged:: 0.6 + Errors due to an inability to find a local configuration file are ignored. + +.. autofunction:: west.configuration.update_config + +.. py:data:: west.configuration.config + + Module-global ConfigParser instance for the current configuration. This + should be initialized with :py:func:`west.configuration.read_config` before + being read. .. _west-apis-log: west.log -======== +******** .. automodule:: west.log :members: set_verbosity, VERBOSE_NONE, VERBOSE_NORMAL, VERBOSE_VERY, VERBOSE_EXTREME, dbg, inf, wrn, err, die @@ -59,18 +141,69 @@ west.log .. _west-apis-manifest: west.manifest -============= +************* .. automodule:: west.manifest - :members: manifest_path, Manifest, Defaults, Remote, Project, SpecialProject, MalformedManifest, MalformedConfig, MANIFEST_SECTIONS, MANIFEST_PROJECT_INDEX, MANIFEST_REV_BRANCH, QUAL_MANIFEST_REV_BRANCH + +.. autodata:: MANIFEST_PROJECT_INDEX + +.. autodata:: MANIFEST_REV_BRANCH + +.. autodata:: QUAL_MANIFEST_REV_BRANCH + +.. autofunction:: west.manifest.manifest_path + +.. autoclass:: west.manifest.Manifest + + .. automethod:: from_file + + .. automethod:: from_data + + .. automethod:: __init__ + + .. automethod:: get_remote + + .. automethod:: as_frozen_dict + +.. autoclass:: west.manifest.Defaults + :members: + :member-order: groupwise + +.. autoclass:: west.manifest.Remote + :members: + :member-order: groupwise + +.. autoclass:: west.manifest.Project + :members: + :member-order: groupwise + +.. autoclass:: west.manifest.ManifestProject + :members: + :member-order: groupwise + +.. versionadded:: 0.6 + +.. autoclass:: west.manifest.MalformedManifest + :show-inheritance: + +.. autoclass:: west.manifest.MalformedConfig + :show-inheritance: .. _west-apis-util: west.util -========= +********* + +.. canon_path(), escapes_directory(), etc. intentionally not documented here. .. automodule:: west.util - :members: west_dir, west_topdir, WestNotFound + +.. autofunction:: west.util.west_dir + +.. autofunction:: west.util.west_topdir + +.. autoclass:: west.util.WestNotFound + :show-inheritance: .. _west #38: https://github.com/zephyrproject-rtos/west/issues/38 From a0ea31195ce07a03071e441b97e959917d32884b Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 12 Aug 2019 13:24:11 +0200 Subject: [PATCH 046/226] doc: west: Fix west completion docs west completion is an extension command, and therefore requires the user to be in a zephyr installation in order to be available. Signed-off-by: Carles Cufi --- doc/guides/west/install.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/guides/west/install.rst b/doc/guides/west/install.rst index 523fb852..d116e3bd 100644 --- a/doc/guides/west/install.rst +++ b/doc/guides/west/install.rst @@ -41,8 +41,8 @@ completion script and have it sourced every time you enter a new shell session. To obtain the completion script you can use the ``west completion`` command:: - cd ~ - west completion bash > west-completion.bash + cd /path/to/zephyr/ + west completion bash > ~/west-completion.bash .. note:: From e784f488def0aa9ff00b8373b3d544b9ecaab849 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 28 Aug 2019 14:06:45 -0600 Subject: [PATCH 047/226] doc: west: add some missing information There's missing overview documentation for some miscellaneous commands. Add it. Signed-off-by: Marti Bolivar --- doc/guides/west/repo-tool.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index e5350133..42dfd3b0 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -244,17 +244,22 @@ Miscellaneous Commands ====================== West has a few more commands for managing the multi-repo, which are briefly -discussed here. +discussed here. Run ``west -h`` for detailed help. -- ``west list``: Lists project information from the manifest (URL, revision, - path, etc.), along with other manifest-related information. +- ``west list [-f FORMAT] [PROJECT ...]``: Lists project information from the + manifest file, such as URL, revision, path, etc. The printed information can + be controlled using the ``-f`` option. - ``west manifest --freeze [-o outfile]``: Save a "frozen" representation of the current manifest; all ``revision`` fields are converted to SHAs based on the current ``manifest-rev`` branches. +- ``west manifest --validate``: Ensure the current manifest file is + well-formed. Print information about what's wrong and fail the process in + case of error. + - ``west diff [PROJECT ...]``: Runs a multi-repo ``git diff`` - for the specified projects (default: all cloned projects). + for the specified projects. - ``west status [PROJECT ...]``: Like ``west diff``, for running ``git status``. @@ -268,6 +273,8 @@ discussed here. forall -c 'git --options'``. Note that ``west forall`` can be used to run any command, though, not just Git commands. +- ``west help ``: this is equivalent to ``west -h``. + .. _PyPI: https://pypi.org/project/west/ From bfc3b96f6ee19ff8cc2f7a0af2b5b85dbe0419c8 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 28 Aug 2019 14:07:38 -0600 Subject: [PATCH 048/226] doc: west: add v0.6.1 documentation West v0.6.1 has been released. The main feature is that "west update" now avoids communicating with the network by default when project revisions have already been fetched. This allows for offline operation and significantly speeds up the command (it's 10 times faster on my machine and home network). There are other miscellaneous changes as well; document them also. Signed-off-by: Marti Bolivar --- doc/guides/west/config.rst | 7 +++++ doc/guides/west/release-notes.rst | 43 ++++++++++++++++++++++++++- doc/guides/west/repo-tool.rst | 26 ++++++++++++---- doc/guides/west/west-apis.rst | 49 ++++++++++++++++++++++++++----- 4 files changed, 112 insertions(+), 13 deletions(-) diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index 67c3758d..9b87b0a0 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -139,6 +139,13 @@ commands are documented in the pages for those commands. - String, relative path from the :term:`west installation` root directory to the manifest repository used by ``west update`` and other commands which parse the manifest. Set locally by ``west init``. + * - ``update.fetch`` + - String, one of ``"smart"`` (the default behavior starting in v0.6.1) or + ``"always"`` (the previous behavior). If set to ``"smart"``, the + :ref:`west update ` command will skip fetching + from project remotes when those projects' revisions in the manifest file + are SHAs or tags which are already available locally. The ``"always"`` + behavior is to unconditionally fetch from the remote. * - ``zephyr.base`` - String, default value to set for the :envvar:`ZEPHYR_BASE` environment variable while the west command is running. By default, this is set to diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index cb4ebc7e..78badca2 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,7 +1,48 @@ West Release Notes ################## -v0.6.x +v0.6.1 +****** + +The user-visible features in this point release are: + +- The `west update ` command has a new ``--fetch`` + command line flag and ``update.fetch`` :ref:`configuration option + `. The default value, "smart", skips fetching SHAs and tags + which are available locally. +- Better and more consistent error-handling in the ``west diff``, ``west + status``, ``west forall``, and ``west update`` commands. Each of these + commands can operate on multiple projects; if a subprocess related to one + project fails, these commands now continue to operate on the rest of the + projects. All of them also now report a nonzero error code from the west + process if any of these subprocesses fails (this was previously not true of + ``west forall`` in particular). +- The :ref:`west manifest ` command also handles errors + better. +- The :ref:`west list ` command now works even when the + projects are not cloned, as long as its format string only requires + information which can be read from the manifest file. It still fails if the + format string requires data stored in the project repository, e.g. if it + includes the ``{sha}`` format string key. +- Commands and options which operate on git revisions now accept abbreviated + SHAs. For example, ``west init --mr SHA_PREFIX`` now works. Previously, the + ``--mr`` argument needed to be the entire 40 character SHA if it wasn't a + branch or a tag. + +The developer-visible changes to the :ref:`west-apis` are: + +- west.log.banner(): new +- west.log.small_banner(): new +- west.manifest.Manifest.get_projects(): new +- west.manifest.Project.is_cloned(): new +- west.commands.WestCommand instances can now access the parsed + Manifest object via a new self.manifest property during the + do_run() call. If read, it returns the Manifest object or + aborts the command if it could not be parsed. +- west.manifest.Project.git() now has a capture_stderr kwarg + + +v0.6.0 ****** - No separate bootstrapper diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 42dfd3b0..c5cbe93a 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -155,6 +155,8 @@ This distribution also includes a launcher executable, also named ``west``. When west is installed, the launcher is placed by :file:`pip3` somewhere in the user's ``PATH``. This is the command-line entry point. +.. _west-manifest-rev: + The ``manifest-rev`` branch *************************** @@ -223,13 +225,27 @@ important to understand. (``-m`` defaults to https://github.com/zephyrproject-rtos/zephyr, and the ``-mr`` default is overridden to ``v1.15.0``). -- ``west update [--rebase] [--keep-descendants] [--exclude-west] [PROJECT - ...]``: clone and update the specified projects based +- ``west update [--fetch {always,smart}] [--rebase] [--keep-descendants] + [PROJECT ...]``: clone and update the specified projects based on the current :term:`west manifest`. - This command parses the manifest, clones any project repositories that are - not already present locally, and checks out the project revisions specified - in the manifest file, updating ``manifest-rev`` branches along the way. + By default, this command: + + #. Parses the manifest file, :file:`west.yml` + #. Clones any project repositories that are not already present locally + #. Fetches any project revisions in the manifest file which are not already + pulled from the remote + #. Sets each project's :ref:`manifest-rev ` branch to the + current manifest revision + #. Checks out those revisions in local working trees + + To operate on a subset of projects only, specify them using the ``PROJECT`` + positional arguments, which can be either project names as given in the + manifest file, or paths to the local project clones. + + To force this command to fetch from project remotes even if the revisions + appear to be available locally, either use ``--fetch always`` or set the + ``update.fetch`` :ref:`configuration option ` to ``"always"``. For safety, ``west update`` uses ``git checkout --detach`` to check out a detached ``HEAD`` at the manifest revision for each updated project, leaving diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 070f9892..b474edfa 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -41,14 +41,14 @@ provided. .. automethod:: __init__ - .. versionadded:: 0.6 + .. versionadded:: 0.6.0 The *requires_installation* parameter. Methods: .. automethod:: run - .. versionchanged:: 0.6 + .. versionchanged:: 0.6.0 The *topdir* argument was added. .. automethod:: add_parser @@ -86,6 +86,16 @@ provided. The argument parser created by calling ``WestCommand.add_parser()``. + Instance properties: + + .. py:attribute:: manifest + + A read-only property which returns the :py:class:`west.manifest.Manifest` + instance for the current manifest file or aborts the program if one was + not provided. This is only safe to use from the ``do_run()`` method. + + .. versionadded:: 0.6.1 + .. autoclass:: west.commands.CommandError :show-inheritance: @@ -119,7 +129,7 @@ west.configuration .. autofunction:: west.configuration.read_config -.. versionchanged:: 0.6 +.. versionchanged:: 0.6.0 Errors due to an inability to find a local configuration file are ignored. .. autofunction:: west.configuration.update_config @@ -136,7 +146,7 @@ west.log ******** .. automodule:: west.log - :members: set_verbosity, VERBOSE_NONE, VERBOSE_NORMAL, VERBOSE_VERY, VERBOSE_EXTREME, dbg, inf, wrn, err, die + :members: set_verbosity, VERBOSE_NONE, VERBOSE_NORMAL, VERBOSE_VERY, VERBOSE_EXTREME, dbg, inf, wrn, err, die, banner, small_banner .. _west-apis-manifest: @@ -163,6 +173,10 @@ west.manifest .. automethod:: get_remote + .. automethod:: get_projects + + .. versionadded:: 0.6.1 + .. automethod:: as_frozen_dict .. autoclass:: west.manifest.Defaults @@ -174,14 +188,35 @@ west.manifest :member-order: groupwise .. autoclass:: west.manifest.Project - :members: - :member-order: groupwise + + .. automethod:: __init__ + + .. automethod:: as_dict + + .. automethod:: format + + .. automethod:: git + + .. versionchanged:: 0.6.1 + The ``capture_stderr`` kwarg. + + .. automethod:: sha + + .. automethod:: is_ancestor_of + + .. automethod:: is_cloned + + .. versionadded:: 0.6.1 + + .. automethod:: is_up_to_date_with + + .. automethod:: is_up_to_date .. autoclass:: west.manifest.ManifestProject :members: :member-order: groupwise -.. versionadded:: 0.6 +.. versionadded:: 0.6.0 .. autoclass:: west.manifest.MalformedManifest :show-inheritance: From 3d62ef688f26c53b200b428c76eec96a7140d123 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 28 Aug 2019 00:42:01 -0600 Subject: [PATCH 049/226] doc: west: add tl;dr for moving to west and troubleshooting These are based on user feedback on slack and the mailing list. Signed-off-by: Marti Bolivar --- doc/guides/west/index.rst | 2 + doc/guides/west/moving-to-west.rst | 57 +++++++++++++++++++++++++++++ doc/guides/west/troubleshooting.rst | 51 ++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 doc/guides/west/moving-to-west.rst create mode 100644 doc/guides/west/troubleshooting.rst diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 4f27fd14..e7828e22 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -34,6 +34,8 @@ context about the tool. :maxdepth: 1 install.rst + moving-to-west.rst + troubleshooting.rst repo-tool.rst manifest.rst config.rst diff --git a/doc/guides/west/moving-to-west.rst b/doc/guides/west/moving-to-west.rst new file mode 100644 index 00000000..51e8d449 --- /dev/null +++ b/doc/guides/west/moving-to-west.rst @@ -0,0 +1,57 @@ +.. _moving-to-west: + +Moving to West +############## + +To convert a "pre-west" Zephyr setup on your computer to west, follow these +steps. If you are starting from scratch, use the :ref:`getting_started` +instead. See :ref:`west-troubleshooting` for advice on common issues. + +#. Install west. + + On Linux:: + + pip3 install --user -U west + + On Windows and macOS:: + + pip3 install -U west + + For details, see :ref:`west-install`. + +#. Move your zephyr repository to a new :file:`zephyrproject` parent directory, + and change directory there. + + On Linux and macOS:: + + mkdir zephyrproject + mv zephyr zephyrproject + cd zephyrproject + + On Windows ``cmd.exe``:: + + mkdir zephyrproject + move zephyr zephyrproject + chdir zephyrproject + + The name :file:`zephyrproject` is recommended, but you can choose any name + with no spaces anywhere in the path. + +#. Create a :ref:`west installation ` using the zephyr + repository as a local manifest repository:: + + west init -l zephyr + + This creates :file:`zephyrproject/.west`, marking the root of your + installation, and does some other setup. It will not change the contents of + the zephyr repository in any way. + +#. Clone the rest of the repositories used by zephyr:: + + west update + + **Make sure to run this command whenever you pull zephyr.** Otherwise, your + local repositories will get out of sync. (Run ``west list`` for current + information on these repositories.) + +You are done: :file:`zephyrproject` is now set up to use west. diff --git a/doc/guides/west/troubleshooting.rst b/doc/guides/west/troubleshooting.rst new file mode 100644 index 00000000..1f1fdc21 --- /dev/null +++ b/doc/guides/west/troubleshooting.rst @@ -0,0 +1,51 @@ +.. _west-troubleshooting: + +Troubleshooting West +#################### + +This page covers common issues with west and how to solve them. + +"invalid choice: 'post-init'" +***************************** + +If you see this error when running ``west init``: + +.. code-block:: none + + west: error: argument : invalid choice: 'post-init' + (choose from 'init', 'update', 'list', 'manifest', 'diff', + 'status', 'forall', 'config', 'selfupdate', 'help') + +Then you have an old version of west installed, and are trying to use it in an +installation that requires a more recent version. + +The easiest way to resolve this issue is to upgrade west and retry as follows: + +#. Install the latest west with the ``-U`` option for ``pip3 install`` as shown + in :ref:`west-install`. + +#. Back up any contents of :file:`zephyrproject/.west/config` that you want to + save. (If you don't have any configuration options set, it's safe to skip + this step.) + +#. Completely remove the :file:`zephyrproject/.west` directory (if you don't, + you will get the "already in an installation" error message discussed next). + +#. Run ``west init`` again. + +"already in an installation" +**************************** + +You may see this error when running ``west init``: + +.. code-block:: none + + FATAL ERROR: already in an installation (), aborting + +If this is unexpected and you're really trying to create a new installation, +then it's likely that west is using the :envvar:`ZEPHYR_BASE` :ref:`environment +variable ` to locate a west installation elsewhere on your system. +This is intentional behavior; it allows you to put your Zephyr applications in +any directory and still use west. + +To resolve this issue, unset :envvar:`ZEPHYR_BASE` and try again. From 00472410c3479b7ed93f9ed25123154747872821 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 4 Sep 2019 07:36:28 -0600 Subject: [PATCH 050/226] doc: west: v0.6.2 fixes a critical v0.6.1 bug All v0.6.1 users must upgrade. Add release notes blurb. Signed-off-by: Marti Bolivar --- doc/guides/west/release-notes.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 78badca2..d4441f86 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,9 +1,21 @@ West Release Notes ################## +v0.6.2 +****** + +This point release fixes an error in the behavior of ``west +update --fetch=smart``, introduced in v0.6.1. + +All v0.6.1 users must upgrade. + v0.6.1 ****** +.. warning:: + + Do not use this point release. Make sure to use v0.6.2 instead. + The user-visible features in this point release are: - The `west update ` command has a new ``--fetch`` From 85d647d81106f6195d49dda17ed1bfdc427bb094 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 4 Oct 2019 12:23:55 -0700 Subject: [PATCH 051/226] doc: add more cross-references/examples for DT overlays Device tree overlays are a bit of a stumbling block. Try to add more cross-references and examples for how to use them to the application development doc and the west build page. Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 61 +++++++++++++++++---------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 3599f1f9..472bd692 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -76,6 +76,13 @@ Examples Here are some ``west build`` usage examples, grouped by area. +Forcing CMake to Run Again +-------------------------- + +To force a CMake re-run, use the ``--cmake`` (or ``--c``) option:: + + west build -c + Setting a Default Board ----------------------- @@ -110,11 +117,8 @@ With the above, running ``west build -b reel_board samples/hello_world`` will use build directory :file:`build/reel_board/hello_world`. See :ref:`west-building-config` for more details on this option. -Controlling the Build System ----------------------------- - -There are several ways to control the build system generated and used by ``west -build``. +Setting the Build System Target +------------------------------- To specify the build system target to run, use ``--target`` (or ``-t``). @@ -133,10 +137,16 @@ all the files in the build directory:: west build -t pristine -To have ``west build`` run the ``pristine`` target before re-running CMake to -generate a build system, use the ``--pristine`` (or ``-p``) option. For -example, to switch board and application (which requires a pristine build -directory) in one command:: +Pristine Builds +--------------- + +A *pristine* build directory is essentially a new build directory. All +byproducts from previous builds have been removed. + +To have ``west build`` make the build directory pristine before re-running +CMake to generate a build system, use the ``--pristine`` (or ``-p``) +option. For example, to switch board and application (which requires a pristine +build directory) in one command:: west build -b qemu_x86 samples/philosophers west build -p -b reel_board samples/hello_world @@ -151,22 +161,28 @@ To let west decide for you if a pristine build is needed, use ``-p auto``:: permanent. .. _west-building-generator: +.. _west-building-cmake-args: + +Additional CMake Arguments +-------------------------- -To add additional arguments to the CMake invocation performed by ``west +To pass additional arguments to the CMake invocation performed by ``west build``, pass them after a ``--`` at the end of the command line. +.. important:: + + Passing additional CMake arguments like this forces ``west build`` to re-run + CMake, even if a build system has already been generated. + + After using ``--`` once to generate the build directory, use ``west build -d + `` on subsequent runs to do incremental builds. + For example, to use the Unix Makefiles CMake generator instead of Ninja (which ``west build`` uses by default), run:: west build -b reel_board -- -G'Unix Makefiles' -.. note:: - - Passing additional CMake arguments like this forces ``west build`` to re-run - CMake, even if a build system has already been generated. - -As another example, to use Unix Makefiles and enable the -`CMAKE_VERBOSE_MAKEFILE`_ option:: +To use Unix Makefiles and set `CMAKE_VERBOSE_MAKEFILE`_ to ``ON``:: west build -b reel_board -- -G'Unix Makefiles' -DCMAKE_VERBOSE_MAKEFILE=ON @@ -174,14 +190,15 @@ Notice how the ``--`` only appears once, even though multiple CMake arguments are given. All command-line arguments to ``west build`` after a ``--`` are passed to CMake. -As a final example, to merge the :file:`file.conf` Kconfig fragment into your -build's :file:`.config`:: +To set :ref:`DTC_OVERLAY_FILE ` to :file:`enable-modem.overlay`, +using that file as a :ref:`device tree overlay `:: - west build -- -DOVERLAY_CONFIG=file.conf + west build -b reel_board -- -DDTC_OVERLAY_FILE=enable-modem.overlay -To force a CMake re-run, use the ``--cmake`` (or ``--c``) option:: +To merge the :file:`file.conf` Kconfig fragment into your build's +:file:`.config`:: - west build -c + west build -- -DOVERLAY_CONFIG=file.conf .. _west-building-config: From 9d16549ca96486d65991b65ea1ad920d9ec6d204 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 7 Oct 2019 10:37:09 -0700 Subject: [PATCH 052/226] doc: s/device tree/devicetree/ DTSpec writes this as a single word, presumably to make it easier to grep for / more precise. Follow along in the rest of the docs now that our main DT docs page agrees with this usage. Signed-off-by: Marti Bolivar --- doc/guides/west/build-flash-debug.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 472bd692..5227a137 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -191,7 +191,7 @@ are given. All command-line arguments to ``west build`` after a ``--`` are passed to CMake. To set :ref:`DTC_OVERLAY_FILE ` to :file:`enable-modem.overlay`, -using that file as a :ref:`device tree overlay `:: +using that file as a :ref:`devicetree overlay `:: west build -b reel_board -- -DDTC_OVERLAY_FILE=enable-modem.overlay From e64510ab96d07070645e53fc6e658ae235990ef5 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 7 Oct 2019 13:43:35 -0700 Subject: [PATCH 053/226] doc: west fixes and updates to manifest.rst Some of this information is stale and needs to be fixed. Try to make a few other things clearer while we're here. Signed-off-by: Marti Bolivar --- doc/guides/west/manifest.rst | 204 ++++++++++++++++------------------- 1 file changed, 94 insertions(+), 110 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 59d15e43..3494d8f9 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -67,73 +67,32 @@ Notice the following important details: Manifest Files ************** -A west manifest is a YAML file named :file:`west.yml`. Manifests have two -top-level "sections", ``west`` and ``manifest``, like this: - -.. code-block:: yaml - - west: - # contents of west section - manifest: - # contents of manifest section - -In YAML terms, the manifest file contains a mapping, with two keys relevant to -west at top level. These keys are the scalar strings ``west`` and -``manifest``. Their contents are described next. - -West Section -============ - -.. note:: - - Support for this feature will be removed in a future version of west, when - the west repository is no longer cloned into the installation. - -The ``west`` section specifies the URL and revision of the west repository -which is cloned into the installation. For example: - -.. code-block:: yaml - - west: - url: https://example.com/west - revision: v0.5.6 - -This specifies cloning the west repository from URL -``https://example.com/west`` (any URL accepted by ``git clone`` will work), at -revision ``v0.5.6``. The revision can be a Git branch, tag, or SHA. - -That is, the west section also contains a mapping, with permitted keys ``url`` -and ``revision``. These specify the fetch URL and Git revision for the west -repository to clone into the installation, as described in -:ref:`west-struct`. If not given, the default URL is -https://github.com/zephyrproject-rtos/west, and the default revision is -``master``. - -The file :file:`west-schema.yml` in the west source code repository contains a -pykwalify schema for this section's contents. - -Manifest Section -================ - -This is the main section in the manifest file. There are four subsections: -``defaults``, ``remotes``, ``projects``, and ``self``. In YAML terms, the value -of the ``manifest`` key is also a mapping, with these "subsections" as keys. -For example: +A west manifest is a YAML file named :file:`west.yml`. Manifests have a +top-level ``manifest`` section with some subsections, like this: .. code-block:: yaml manifest: defaults: - # contents of defaults subsection + # default project attributes (optional) remotes: - # contents of remotes subsection + # short names for project URLs (optional) projects: - # contents of projects subsection + # a list of projects managed by west (mandatory) self: - # contents of self subsection + # configuration related to the manifest repository itself, + # i.e. the repository containing west.yml (optional) + +In YAML terms, the manifest file contains a mapping, with a ``manifest`` +key. Any other keys and their contents are ignored (west v0.5 also required a +``west`` key, but this is ignored starting with v0.6). + +There are four subsections: ``defaults``, ``remotes``, ``projects``, and +``self``. In YAML terms, the value of the ``manifest`` key is also a mapping, +with these "subsections" as keys. Only ``projects`` is mandatory: this is the +list of repositories managed by west and their metadata. -The ``remotes`` and ``projects`` subsections are the only mandatory ones, so -we'll cover them first. +We'll cover the ``remotes`` and ``projects`` subsections in detail first. The ``remotes`` subsection contains a sequence which specifies the base URLs where projects can be fetched from. Each sequence element has a name and a "URL @@ -156,82 +115,105 @@ bases are respectively ``https://example.com/base1`` and you might use ``git@example.com:base1`` if ``remote1`` supported Git over SSH as well. Anything acceptable to Git will work. -The ``projects`` subsection contains a sequence describing the -project repositories in the west installation. Each project has a -name and a remote; the project's name is appended to the remote URL -base to form the Git fetch URL west uses to clone the project and keep -it up to date. Here is a simple example; we'll assume the ``remotes`` -given above. +The ``projects`` subsection contains a sequence describing the project +repositories in the west installation. Every project has a unique name. You can +specify what Git remote URLs to use when cloning and fetching the projects, +what revisions to track, and where the project should be stored on the local +file system. + +Here is an example. We'll assume the ``remotes`` given above. + +.. Note: if you change this example, keep the equivalent manifest below in + sync. .. code-block:: yaml manifest: - # [...] + # [... same remotes as above...] projects: - name: proj1 remote: remote1 path: extra/project-1 - name: proj2 - remote: remote1 + repo-path: my-path + remote: remote2 revision: v1.3 - name: proj3 - remote: remote2 + url: https://github.com/user/project-three revision: abcde413a111 -This example has three projects: +In this manifest: - ``proj1`` has remote ``remote1``, so its Git fetch URL is - ``https://example.com/base1/proj1`` (note that west adds the ``/`` between - the URL base and project name). This project will be cloned at path - ``extra/project-1`` relative to the west installation's root directory. - Since the project has no ``revision``, the current tip of the ``master`` - branch will be checked out as a detached ``HEAD``. - -- ``proj2`` has the same remote, so its fetch URL is - ``https://example.com/base1/proj2``. Since the project has no ``path`` - specified, it will be cloned at ``proj2`` (i.e. a project's ``name`` is used - as its default ``path``). The commit pointed to by the ``v1.3`` tag will be - checked out. - -- ``proj3`` has fetch URL ``https://example.com/base2/proj3`` and will be - cloned at path ``proj3``. Commit ``abcde413a111`` will be checked out. - -Each element in the ``projects`` sequence can contain the following keys. Some -of the description refers to the ``defaults`` subsection, which will be -described next. - -- ``name``: Mandatory, the name of the project. The fetch URL is formed as - remote url-base + '/' + ``name``. The name cannot be one of the reserved - values "west" and "manifest". -- ``remote``: The name of the project's remote. If not given, the ``remote`` - value in the ``defaults`` subsection is tried next. If both are missing, the + ``https://example.com/base1/proj1``. The remote ``url-base`` is appended with + a ``/`` and the project ``name`` to form the URL. + + Locally, this project will be cloned at path ``extra/project-1`` relative to + the west installation's root directory, since it has an explicit ``path`` + attribute with this value. + + Since the project has no ``revision`` specified, ``master`` is used by + default. The current tip of this branch will be fetched and checked out as a + detached ``HEAD`` when west next updates this project. + +- ``proj2`` has a ``remote`` and a ``repo-path``, so its fetch URL is + ``https://example.com/base2/my-path``. The ``repo-path`` attribute, if + present, overrides the default ``name`` when forming the fetch URL. + + Since the project has no ``path`` attribute, its ``name`` is used by + default. It will be cloned into a directory named ``proj2``. The commit + pointed to by the ``v1.3`` tag will be checked out when west updates the + project. + +- ``proj3`` has an explicit ``url``, so it will be fetched from + ``https://github.com/user/project-three``. + + Its local path defaults to its name, ``proj3``. Commit ``abcde413a111`` will + be checked out when it is next updated. + +The list of project keys and their usage follows. Sometimes we'll refer to the +``defaults`` subsection; it will be described next. + +- ``name``: Mandatory. the name of the project. The name cannot be one of the + reserved values "west" or "manifest". The name must be unique in the manifest + file. +- ``remote`` or ``url``: Mandatory (one of the two, but not both). + + If the project has a ``remote``, that remote's ``url-base`` will be combined + with the project's ``name`` (or ``repo-path``, if it has one) to form the + fetch URL instead. + + If the project has a ``url``, that's the complete fetch URL for the + remote Git repository. + + If the project has neither, the ``defaults`` section must specify a + ``remote``, which will be used as the the project's remote. Otherwise, the manifest is invalid. - ``repo-path``: Optional. If given, this is concatenated on to the remote's ``url-base`` instead of the project's ``name`` to form its fetch URL. -- ``url``: Optional. If given, this is the project's complete fetch URL. - It cannot be combined with either ``remote`` or ``repo-path``. Note that this - overrides any default remote. -- ``revision``: Optional. The current project revision used by ``west update``. - If not given, the value from the ``defaults`` subsection will be used if - present. If both are missing, ``master`` is used. A project revision can be - a branch, tag, or SHA. The names of unqualified branch and tag revisions are - fetched as-is. For qualified refs, like ``refs/heads/foo``, the last - component (``foo``) is used. -- ``path``: Optional. Where to clone the repository locally. If missing, it's - cloned in the west installation's root subdirectory given by the project's - name. + Projects may not have both ``url`` and ``repo-path`` attributes. +- ``revision``: Optional. The Git revision that ``west update`` should check + out. This will be checked out as a detached HEAD by default, to avoid + conflicting with local branch names. If not given, the ``revision`` value + from the ``defaults`` subsection will be used if present. + + A project revision can be a branch, tag, or SHA. The default ``revision`` is + ``master`` if not otherwise specified. +- ``path``: Optional. Relative path specifying where to clone the repository + locally, relative to the top directory in the west installation. If missing, + the project's ``name`` is used as a directory name. - ``clone-depth``: Optional. If given, a positive integer which creates a shallow history in the cloned repository limited to the given number of - commits. + commits. This can only be used if the ``revision`` is a branch or tag. - ``west-commands``: Optional. If given, a relative path to a YAML file within the project which describes additional west commands provided by that project. This file is named :file:`west-commands.yml` by convention. See :ref:`west-extensions` for details. -The ``defaults`` subsection can provide default values for project-related -values. In particular, the default remote name and revision can be specified -here. Another way to write the same manifest we have been describing so far -using ``defaults`` is: +The ``defaults`` subsection can provide default values for project +attributes. In particular, the default remote name and revision can be +specified here. Another way to write the same manifest we have been describing +so far using ``defaults`` is: .. code-block:: yaml @@ -251,8 +233,10 @@ using ``defaults`` is: path: extra/project-1 revision: master - name: proj2 - - name: proj3 + repo-path: my-path remote: remote2 + - name: proj3 + url: https://github.com/user/project-three revision: abcde413a111 Finally, the ``self`` subsection can be used to control the behavior of the From 40c752e24e3b7e119436bf928c4b6ff0819e1a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 9 Dec 2019 11:05:11 -0800 Subject: [PATCH 054/226] scripts: add new west build "build.cmake-args" config option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option, if set, will add arguments to CMake whenever a new build system is being generated. It doesn't affect other invocations of CMake, such as when cmake(1) is run in build tool mode to actually compile the application. See the documentation changes for details. Signed-off-by: Martí Bolívar --- doc/guides/west/build-flash-debug.rst | 86 ++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 5227a137..070e5e0e 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -137,6 +137,8 @@ all the files in the build directory:: west build -t pristine +.. _west-building-pristine: + Pristine Builds --------------- @@ -160,11 +162,21 @@ To let west decide for you if a pristine build is needed, use ``-p auto``:: You can run ``west config build.pristine auto`` to make this setting permanent. +.. _west-building-verbose: + +Verbose Builds +-------------- + +To print the CMake and compiler commands run by ``west build``, use the global +west verbosity option, ``-v``:: + + west -v build -b reel_board samples/hello_world + .. _west-building-generator: .. _west-building-cmake-args: -Additional CMake Arguments --------------------------- +One-Time CMake Arguments +------------------------ To pass additional arguments to the CMake invocation performed by ``west build``, pass them after a ``--`` at the end of the command line. @@ -200,6 +212,72 @@ To merge the :file:`file.conf` Kconfig fragment into your build's west build -- -DOVERLAY_CONFIG=file.conf +.. _west-building-cmake-config: + +Permanent CMake Arguments +------------------------- + +The previous section describes how to add CMake arguments for a single ``west +build`` command. If you want to save CMake arguments for ``west build`` to use +every time it generates a new build system instead, you should use the +``build.cmake-args`` configuration option. Whenever ``west build`` runs CMake +to generate a build system, it splits this option's value according to shell +rules and includes the results in the ``cmake`` command line. + +Remember that, by default, ``west build`` **tries to avoid generating a new +build system if one is present** in your build directory. Therefore, you need +to either delete any existing build directories or do a :ref:`pristine build +` after setting ``build.cmake-args`` to make sure it +will take effect. + +For example, to always enable :makevar:`CMAKE_EXPORT_COMPILE_COMMANDS`, you can +run:: + + west config build.cmake-args -- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + +(The extra ``--`` is used to force the rest of the command to be treated as a +positional argument. Without it, :ref:`west config ` would +treat the ``-DVAR=VAL`` syntax as a use of its ``-D`` option.) + +To enable :makevar:`CMAKE_VERBOSE_MAKEFILE`, so CMake always produces a verbose +build system:: + + west config build.cmake-args -- -DCMAKE_VERBOSE_MAKEFILE=ON + +To save more than one argument in ``build.cmake-args``, use a single string +whose value can be split into distinct arguments (``west build`` uses the +Python function `shlex.split()`_ internally to split the value). + +.. _shlex.split(): https://docs.python.org/3/library/shlex.html#shlex.split + +For example, to enable both :makevar:`CMAKE_EXPORT_COMPILE_COMMANDS` and +:makevar:`CMAKE_VERBOSE_MAKEFILE`:: + + west config build.cmake-args -- "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_VERBOSE_MAKEFILE=ON" + +If you want to save your CMake arguments in a separate file instead, you can +combine CMake's ``-C `` option with ``build.cmake-args``. For +instance, another way to set the options used in the previous example is to +create a file named :file:`~/my-cache.cmake` with the following contents: + +.. code-block:: cmake + + set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "") + set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "") + +Then run:: + + west config build.cmake-args "-C ~/my-cache.cmake" + +See the `cmake(1) manual page`_ and the `set() command`_ documentation for +more details. + +.. _cmake(1) manual page: + https://cmake.org/cmake/help/latest/manual/cmake.1.html + +.. _set() command: + https://cmake.org/cmake/help/latest/command/set.html + .. _west-building-config: Configuration Options @@ -222,6 +300,10 @@ You can :ref:`configure ` ``west build`` using these options. * - ``build.board_warn`` - Boolean, default ``true``. If ``false``, disables warnings when ``west build`` can't figure out the target board. + * - ``build.cmake-args`` + - String. If present, the value will be split according to shell rules and + passed to CMake whenever a new build system is generated. See + :ref:`west-building-cmake-config`. * - ``build.dir-fmt`` - String, default ``build``. The build folder format string, used by west whenever it needs to create or locate a build folder. The currently From 4c0bee0b304d68ef3b84c68efa15c810f8c57d4c Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Mon, 18 Nov 2019 10:56:50 +0100 Subject: [PATCH 055/226] global: Remove leading/trailing blank lines in files Remove leading/trailing blank lines in .c, .h, .py, .rst, .yml, and .yaml files. Will avoid failures with the new CI test in https://github.com/zephyrproject-rtos/ci-tools/pull/112, though it only checks changed files. Move the 'target-notes' target in boards/xtensa/odroid_go/doc/index.rst to get rid of the trailing blank line there. It was probably misplaced. Signed-off-by: Ulf Magnusson --- doc/guides/west/release-notes.rst | 1 - doc/guides/west/west-not-found.rst | 1 - doc/guides/west/zephyr-cmds.rst | 1 - 3 files changed, 3 deletions(-) diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index d4441f86..3d00d7a0 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -170,4 +170,3 @@ historical interest only. .. _west v0.5.x documentation: https://docs.zephyrproject.org/1.14.0/guides/west/index.html - diff --git a/doc/guides/west/west-not-found.rst b/doc/guides/west/west-not-found.rst index d54c3b4f..76cc6d79 100644 --- a/doc/guides/west/west-not-found.rst +++ b/doc/guides/west/west-not-found.rst @@ -13,4 +13,3 @@ West APIs The west APIs are not documented since either west was missing or the zephyr repository was not initialized using west during the documentation build. - diff --git a/doc/guides/west/zephyr-cmds.rst b/doc/guides/west/zephyr-cmds.rst index 92f0b6a3..707fd12b 100644 --- a/doc/guides/west/zephyr-cmds.rst +++ b/doc/guides/west/zephyr-cmds.rst @@ -36,4 +36,3 @@ flag:: Additional help about the formatting options can be found by running:: west boards -h - From 6cdc3f72a07fe9ddeeccecb3ba172fa3471d861b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 3 Apr 2019 15:58:25 -0600 Subject: [PATCH 056/226] doc: west: move manifest command docs to manifest.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is just a prep work commit for documenting ``west manifest --merge``. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 34 ++++++++++++++++++++++++++++++---- doc/guides/west/repo-tool.rst | 4 +--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 3494d8f9..68c94cb0 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -3,10 +3,10 @@ West Manifests ############## -This page contains detailed information about west's multiple repository model -and manifest files. For API documentation on the ``west.manifest`` module, see -:ref:`west-apis-manifest`. For a more general introduction and command -overview, see :ref:`west-multi-repo`. +This page contains detailed information about west's multiple repository model, +manifest files, and the ``west manifest`` command. For API documentation on the +``west.manifest`` module, see :ref:`west-apis-manifest`. For a more general +introduction and command overview, see :ref:`west-multi-repo`. .. _west-mr-model: @@ -271,3 +271,29 @@ repository root. The pykwalify schema :file:`manifest-schema.yml` in the west source code repository is used to validate the manifest section. + +.. _west-manifest-cmd: + +Manifest Command +**************** + +The ``west manifest`` command can be used to manipulate manifest files. +It takes an action, and action-specific arguments. + +The following sections describe each action and provides a basic signature for +simple uses. Run ``west manifest --help`` for full details on all options. + +Freezing Manifests +================== + +The ``--freeze`` action outputs a frozen manifest: + +.. code-block:: none + + west manifest --freeze [-o outfile] + +A "frozen" manifest is a manifest file where every project's revision is a SHA. +You can use ``--freeze`` to produce a frozen manifest that's equivalent to your +current manifest file. The ``-o`` option specifies an output file; if not +given, standard output is used. + diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index c5cbe93a..2e06c37e 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -266,9 +266,7 @@ discussed here. Run ``west -h`` for detailed help. manifest file, such as URL, revision, path, etc. The printed information can be controlled using the ``-f`` option. -- ``west manifest --freeze [-o outfile]``: Save a "frozen" representation of - the current manifest; all ``revision`` fields are converted to SHAs based on - the current ``manifest-rev`` branches. +- ``west manifest``: Manipulates manifest files. See :ref:`west-manifest-cmd`. - ``west manifest --validate``: Ensure the current manifest file is well-formed. Print information about what's wrong and fail the process in From 5ca9597e6e295959fefd374da7cfbfa686c46e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 10 Oct 2019 13:44:04 -0700 Subject: [PATCH 057/226] doc: west: add docs for west manifest --validate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is supported but undocumented. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 68c94cb0..5911254c 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -297,3 +297,14 @@ You can use ``--freeze`` to produce a frozen manifest that's equivalent to your current manifest file. The ``-o`` option specifies an output file; if not given, standard output is used. +Validating Manifests +==================== + +The ``--validate`` action either succeeds if the current manifest file is valid, +or fails with an error: + +.. code-block:: none + + west manifest --validate + +The error message can help diagnose errors. From e90fa879c35217880a71cf780dc98e2faab56f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 7 Oct 2019 13:58:15 -0700 Subject: [PATCH 058/226] doc: west: add "git." prefix to URL hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By request, for clarity. Suggested-by: Carles Cufí Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 5911254c..048b7fb6 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -105,15 +105,15 @@ example: # [...] remotes: - name: remote1 - url-base: https://example.com/base1 + url-base: https://git.example.com/base1 - name: remote2 - url-base: https://example.com/base2 + url-base: https://git.example.com/base2 Above, two remotes are given, with names ``remote1`` and ``remote2``. Their URL -bases are respectively ``https://example.com/base1`` and -``https://example.com/base2``. You can use SSH URL bases as well; for example, -you might use ``git@example.com:base1`` if ``remote1`` supported Git over SSH -as well. Anything acceptable to Git will work. +bases are respectively ``https://git.example.com/base1`` and +``https://git.example.com/base2``. You can use SSH URL bases as well; for +example, you might use ``git@example.com:base1`` if ``remote1`` supported Git +over SSH as well. Anything acceptable to Git will work. The ``projects`` subsection contains a sequence describing the project repositories in the west installation. Every project has a unique name. You can @@ -145,8 +145,8 @@ Here is an example. We'll assume the ``remotes`` given above. In this manifest: - ``proj1`` has remote ``remote1``, so its Git fetch URL is - ``https://example.com/base1/proj1``. The remote ``url-base`` is appended with - a ``/`` and the project ``name`` to form the URL. + ``https://git.example.com/base1/proj1``. The remote ``url-base`` is appended + with a ``/`` and the project ``name`` to form the URL. Locally, this project will be cloned at path ``extra/project-1`` relative to the west installation's root directory, since it has an explicit ``path`` @@ -157,7 +157,7 @@ In this manifest: detached ``HEAD`` when west next updates this project. - ``proj2`` has a ``remote`` and a ``repo-path``, so its fetch URL is - ``https://example.com/base2/my-path``. The ``repo-path`` attribute, if + ``https://git.example.com/base2/my-path``. The ``repo-path`` attribute, if present, overrides the default ``name`` when forming the fetch URL. Since the project has no ``path`` attribute, its ``name`` is used by @@ -224,9 +224,9 @@ so far using ``defaults`` is: remotes: - name: remote1 - url-base: https://example.com/base1 + url-base: https://git.example.com/base1 - name: remote2 - url-base: https://example.com/base2 + url-base: https://git.example.com/base2 projects: - name: proj1 @@ -245,7 +245,7 @@ manifest repository itself. Its value is a map with the following keys: - ``path``: Optional. The path to clone the manifest repository into, relative to the west installation's root directory. If not given, the basename of the path component in the manifest repository URL will be used by default. For - example, if the URL is ``https://example.com/project-repo``, the manifest + example, if the URL is ``https://git.example.com/project-repo``, the manifest repository would be cloned to the directory :file:`project-repo`. - ``west-commands``: Optional. This is analogous to the same key in a From f587b55c51e6e6a301e4fdbeb4076b750c24b3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 7 Oct 2019 14:59:04 -0700 Subject: [PATCH 059/226] doc: west: document manifest import feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit West now supports importing other manifest files. Document the basic behavior. Add a local table of contents for HTML output, to get a quick index of the subsections of the "Manifest Imports" section. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 843 ++++++++++++++++++++++++++++++++++- 1 file changed, 841 insertions(+), 2 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 048b7fb6..d0762e90 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -8,6 +8,11 @@ manifest files, and the ``west manifest`` command. For API documentation on the ``west.manifest`` module, see :ref:`west-apis-manifest`. For a more general introduction and command overview, see :ref:`west-multi-repo`. +.. only:: html + + .. contents:: + :depth: 3 + .. _west-mr-model: Multiple Repository Model @@ -64,6 +69,8 @@ Notice the following important details: name as a manifest revision, at the cost of being able to bisect manifest repository history. +.. _west-manifest-files: + Manifest Files ************** @@ -102,7 +109,7 @@ example: .. code-block:: yaml manifest: - # [...] + # ... remotes: - name: remote1 url-base: https://git.example.com/base1 @@ -209,6 +216,9 @@ The list of project keys and their usage follows. Sometimes we'll refer to the the project which describes additional west commands provided by that project. This file is named :file:`west-commands.yml` by convention. See :ref:`west-extensions` for details. +- ``import``: Optional. If ``true``, imports projects from manifest files in + the given repository into the current manifest. See + :ref:`west-manifest-import` for more details. The ``defaults`` subsection can provide default values for project attributes. In particular, the default remote name and revision can be @@ -251,13 +261,17 @@ manifest repository itself. Its value is a map with the following keys: - ``west-commands``: Optional. This is analogous to the same key in a project sequence element. +- ``import``: Optional. This is also analogous to the ``projects`` key, but + allows importing projects from other files in the manifest repository. See + :ref:`west-manifest-import`. + As an example, let's consider this snippet from the zephyr repository's :file:`west.yml`: .. code-block:: yaml manifest: - # [...] + # ... self: path: zephyr west-commands: scripts/west-commands.yml @@ -272,6 +286,808 @@ repository root. The pykwalify schema :file:`manifest-schema.yml` in the west source code repository is used to validate the manifest section. +.. _west-manifest-import: + +Manifest Imports +**************** + +You can use the ``import`` key briefly described above to include projects from +other manifest files in your :file:`west.yml`. This key can be either a +``project`` or ``self`` section attribute: + +.. code-block:: yaml + + manifest: + projects: + - name: some-project + import: ... + self: + import: ... + +You can use a "self: import:" to load additional files from the repository +containing your :file:`west.yml`. You can use a "project: ... import:" to load +additional files defined in that project's Git history. + +West resolves the final manifest from individual manifest files in this order: + +#. imported files in ``self`` +#. your :file:`west.yml` file +#. imported files in ``projects`` + +During resolution, west ignores projects which have already been defined in +other files. For example, a project named ``foo`` in your :file:`west.yml` +makes west ignore other projects named ``foo`` imported from your ``projects`` +list. + +The ``import`` key can be a boolean, path, mapping, or sequence. We'll describe +these in order, using examples: + +- :ref:`Boolean ` + - :ref:`west-manifest-ex1.1` + - :ref:`west-manifest-ex1.2` + - :ref:`west-manifest-ex1.3` +- :ref:`Relative path ` + - :ref:`west-manifest-ex2.1` + - :ref:`west-manifest-ex2.2` + - :ref:`west-manifest-ex2.3` +- :ref:`Mapping with additional configuration ` + - :ref:`west-manifest-ex3.1` + - :ref:`west-manifest-ex3.2` + - :ref:`west-manifest-ex3.3` +- :ref:`Sequence of paths and mappings ` + - :ref:`west-manifest-ex4.1` + - :ref:`west-manifest-ex4.2` + +A more :ref:`formal description ` of how this works is +last, after the examples. + +Troubleshooting Note +==================== + +If you're using this feature and find west's behavior confusing, try +:ref:`resolving your manifest ` to see the final results +after imports are done. + +.. _west-manifest-import-bool: + +Option 1: Boolean +================= + +This is the easiest way to use ``import``. + +If ``import`` is ``true`` as a ``projects`` attribute, west imports projects +from the :file:`west.yml` file in that project's root directory. If it's +``false`` or missing, it has no effect. For example, this manifest would import +:file:`west.yml` from the ``p1`` git repository at revision ``v1.0``: + +.. code-block:: yaml + + manifest: + # ... + projects: + - name: p1 + revision: v1.0 + import: true # Import west.yml from p1's v1.0 git tag + - name: p2 + import: false # Nothing is imported from p2. + - name: p3 # Nothing is imported from p3 either. + +It's an error to set ``import`` to either ``true`` or ``false`` inside +``self``, like this: + +.. code-block:: yaml + + manifest: + # ... + self: + import: true # Error + +.. _west-manifest-ex1.1: + +Example 1.1: Downstream of a Zephyr release +------------------------------------------- + +You have a source code repository you want to use with Zephyr v1.14.1 LTS. You +want to maintain the whole thing using west. You don't want to modify any of +the mainline repositories. + +In other words, the west installation you want looks like this: + +.. code-block:: none + + my-downstream + ├── .west # west directory + ├── zephyr # mainline zephyr repository + ├── modules # modules from mainline zephyr + │   ├── hal + │   └── [...other directories..] + ├── [ ... other projects ...] # other mainline repositories + └── my-repo # your downstream repository + ├── west.yml + └── [...other files..] + +You can do this with the following :file:`my-repo/west.yml`: + +.. code-block:: yaml + + # my-repo/west.yml: + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v1.14.1 + import: true + +You can then create the installation on your computer like this, assuming +``my-repo`` is hosted at ``https://git.example.com/my-repo``: + +.. code-block:: console + + west init -m https://git.example.com/my-repo my-downstream + cd my-downstream + west update + +After ``west init``, :file:`my-downstream/my-repo` will be cloned. + +After ``west update``, all of the projects defined in the ``zephyr`` +repository's :file:`west.yml` at revision ``v1.14.1`` will be cloned into +:file:`my-downstream` as well. + +You can add and commit any code to :file:`my-repo` you please at this point, +including your own Zephyr applications, drivers, etc. See :ref:`application`. + +.. _west-manifest-ex1.2: + +Example 1.2: "Rolling release" Zephyr downstream +------------------------------------------------ + +This is similar to :ref:`west-manifest-ex1.1`, except we'll use ``revision: +master`` for the zephyr repository: + +.. code-block:: yaml + + # my-repo/west.yml: + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: master + import: true + +You can create the installation in the same way: + +.. code-block:: console + + west init -m https://git.example.com/my-repo my-downstream + cd my-downstream + west update + +This time, whenever you run ``west update``, the special :ref:`manifest-rev +` branch in the ``zephyr`` repository will be updated to +point at a newly fetched ``master`` branch tip from the URL +https://github.com/zephyrproject-rtos/zephyr. + +The contents of :file:`zephyr/west.yml` at the new ``manifest-rev`` will then +be used to import projects from Zephyr. This lets you stay up to date with the +latest changes in the Zephyr project. The cost is that running ``west update`` +will not produce reproducible results, since the remote ``master`` branch can +change every time you run it. + +It's also important to understand that west **ignores your working tree's** +:file:`zephyr/west.yml` entirely when resolving imports. West always uses the +contents of imported manifests as they were committed to the latest +``manifest-rev`` when importing from a project. + +You can only import manifest from the file system if they are in your manifest +repository's working tree. See :ref:`west-manifest-ex2.2` for an example. + +.. _west-manifest-ex1.3: + +Example 1.3: Downstream of a Zephyr release, with module fork +------------------------------------------------------------- + +This manifest is similar to the one in :ref:`west-manifest-ex1.1`, except it: + +- is a downstream of Zephyr 2.0 +- includes a downstream fork of the :file:`modules/hal/nordic` + :ref:`module ` which was included in that release + +.. code-block:: yaml + + # my-repo/west.yml: + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + - name: my-remote + url-base: https://git.example.com + projects: + - name: hal_nordic + remote: my-remote + revision: my-sha + path: modules/hal/nordic + - name: zephyr + remote: zephyrproject-rtos + revision: v2.0.0 + import: true + + # subset of zephyr/west.yml contents at v2.0.0: + manifest: + defaults: + remote: zephyrproject-rtos + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + # ... + - name: hal_nordic + path: modules/hal/nordic + revision: another-sha + +With this manifest file, the project named ``hal_nordic``: + +- is cloned from ``https://git.example.com/hal_nordic`` instead of + ``https://github.com/zephyrproject-rtos/hal_nordic``. +- is updated to commit ``my-sha`` by ``west update``, instead of + the mainline commit ``another-sha`` + +In other words, when your top-level manifest defines a project, like +``hal_nordic``, west will ignore any other definition it finds later on while +resolving imports. + +This does mean you have to copy the ``path: modules/hal/nordic`` value into +:file:`my-repo/west.yml` when defining ``hal_nordic`` there. The value from +:file:`zephyr/west.yml` is ignored entirely. See :ref:`west-manifest-resolve` +for troubleshooting advice if this gets confusing in practice. + +When you run ``west update``, west will: + +- update zephyr's ``manifest-rev`` to point at the ``v2.0.0`` tag +- import :file:`zephyr/west.yml` at that ``manifest-rev`` +- locally check out the ``v2.0.0`` revisions for all zephyr projects except + ``hal_nordic`` +- update ``hal_nordic`` to ``my-sha`` instead of ``another-sha`` + +.. _west-manifest-import-path: + +Option 2: Relative path +======================= + +The ``import`` value can also be a relative path to a manifest file or a +directory containing manifest files. The path is relative to the root directory +of the ``projects`` or ``self`` repository the ``import`` key appears in. + +Here is an example: + +.. code-block:: yaml + + manifest: + projects: + - name: project-1 + revision: v1.0 + import: west.yml + - name: project-2 + revision: master + import: p2-manifests + self: + import: submanifests + +This will import the following: + +- the contents of :file:`project-1/west.yml` at ``manifest-rev``, which points + at tag ``v1.0`` after running ``west update`` +- any YAML files in the directory tree :file:`project-2/p2-manifests` + at the latest ``master``, as fetched by ``west update``, sorted by file name +- YAML files in :file:`submanifests` in your manifest repository, + as they appear on your file system, sorted by file name + +Notice how ``projects`` imports get data from Git using ``manifest-rev``, while +``self`` imports get data from your file system. This is because as usual, west +leaves version control for your manifest repository up to you. + +.. _west-manifest-ex2.1: + +Example 2.1: Downstream of a Zephyr release with explicit path +-------------------------------------------------------------- + +This is an explicit way to write an equivalent manifest to the one in +:ref:`west-manifest-ex1.1`. + +.. code-block:: yaml + + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v1.14.1 + import: west.yml + +The setting ``import: west.yml`` means to use the file :file:`west.yml` inside +the ``zephyr`` project. This example is contrived, but shows the idea. + +This can be useful in practice when the name of the manifest file you want to +import is not :file:`west.yml`. + +.. _west-manifest-ex2.2: + +Example 2.2: Downstream with directory of manifest files +-------------------------------------------------------- + +Your Zephyr downstream has a lot of additional repositories. So many, in fact, +that you want to split them up into multiple manifest files, but keep track of +them all in a single manifest repository, like this: + +.. code-block:: none + + my-repo/ + ├── submanifests + │ ├── 01-libraries.yml + │ ├── 02-vendor-hals.yml + │ └── 03-applications.yml + └── west.yml + +You want to add all the files in :file:`my-repo/submanifests` to the main +manifest file, :file:`my-repo/west.yml`, in addition to projects in +:file:`zephyr/west.yml`. You want to track the latest mainline master +instead of using a fixed revision. + +Here's how: + +.. code-block:: yaml + + # my-repo/west.yml: + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + import: true + self: + import: submanifests + +Manifest files are imported in this order during resolution: + +#. :file:`my-repo/submanifests/01-libraries.yml` +#. :file:`my-repo/submanifests/02-vendor-hals.yml` +#. :file:`my-repo/submanifests/03-applications.yml` +#. :file:`my-repo/west.yml` +#. :file:`zephyr/west.yml` + +.. note:: + + The :file:`.yml` file names are prefixed with numbers in this example to + make sure they are imported in the specified order. + + You can pick arbitrary names. West sorts files in a directory by name before + importing. + +Notice how the manifests in :file:`submanifests` are imported *before* +:file:`my-repo/west.yml` and :file:`zephyr/west.yml`. In general, an ``import`` +in the ``self`` section is processed before the manifest files in ``projects`` +and the main manifest file. + +This means projects defined in :file:`my-repo/submanifests` take highest +precedence. For example, if :file:`01-libraries.yml` defines ``hal_nordic``, +the project by the same name in :file:`zephyr/west.yml` is simply ignored. As +usual, see :ref:`west-manifest-resolve` for troubleshooting advice. + +This may seem strange, but it allows you to redefine projects "after the fact", +as we'll see in the next example. + +.. _west-manifest-ex2.3: + +Example 2.3: Continuous Integration overrides +--------------------------------------------- + +Your continuous integration system needs to fetch and test multiple +repositories in your west installation from a developer's forks instead of your +mainline development trees, to see if the changes all work well together. + +Starting with :ref:`west-manifest-ex2.2`, the CI scripts add a +file :file:`00-ci.yml` in :file:`my-repo/submanifests`, with these contents: + +.. code-block:: yaml + + # my-repo/submanifests/00-ci.yml: + manifest: + projects: + - name: a-vendor-hal + url: https://github.com/a-developer/hal + revision: a-pull-request-branch + - name: an-application + url: https://github.com/a-developer/application + revision: another-pull-request-branch + +The CI scripts run ``west update`` after generating this file in +:file:`my-repo/submanifests`. The projects defined in :file:`00-ci.yml` have +higher precedence than other definitions in :file:`my-repo/submanifests`, +because the name :file:`00-ci.yml` comes before the other file names. + +Thus, ``west update`` always checks out the developer's branches in the +projects named ``a-vendor-hal`` and ``an-application``, even if those same +projects are also defined elsewhere. + +.. _west-manifest-import-map: + +Option 3: Mapping +================= + +The ``import`` key can also contain a mapping with the following keys: + +- ``file``: Optional. The name of the manifest file or directory to import. + This defaults to :file:`west.yml` if not present. +- ``name-whitelist``: Optional. If present, a name or sequence of project names + to include. +- ``path-whitelist``: Optional. If present, a path or sequence of project paths + to match against. This is a shell-style globbing pattern, currently + implemented with `pathlib`_. Note that this means case sensitivity is + platform specific. +- ``name-blacklist``: Optional. Like ``name-whitelist``, but contains project + names to exclude rather than include. +- ``path-blacklist``: Optional. Like ``path-whitelist``, but contains project + paths to exclude rather than include. + +.. _re: https://docs.python.org/3/library/re.html +.. _pathlib: + https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.match + +Whitelists override blacklists if both are given. For example, if a project is +blacklisted by path, then whitelisted by name, it will still be imported. + +.. _west-manifest-ex3.1: + +Example 3.1: Downstream with name whitelist +------------------------------------------- + +Here is a pair of manifest files, representing a mainline and a +downstream. The downstream doesn't want to use all the mainline +projects, however. We'll assume the mainline :file:`west.yml` is +hosted at ``https://git.example.com/mainline/manifest``. + +.. code-block:: yaml + + # mainline west.yml: + manifest: + projects: + - name: mainline-app + path: examples/app + url: https://git.example.com/mainline/app + - name: lib + path: libraries/lib + url: https://git.example.com/mainline/lib + - name: lib2 + path: libraries/lib2 + url: https://git.example.com/mainline/lib2 + + # downstream west.yml: + manifest: + projects: + - name: mainline + url: https://git.example.com/mainline/manifest + import: + name-whitelist: + - mainline-app + - lib2 + - name: downstream-app + url: https://git.example.com/downstream/app + - name: lib3 + path: libraries/lib3 + url: https://git.example.com/downstream/lib3 + +An equivalent manifest in a single file would be: + +.. code-block:: yaml + + manifest: + projects: + - name: mainline + url: https://git.example.com/mainline/manifest + - name: downstream-app + url: https://git.example.com/downstream/app + - name: lib3 + path: libraries/lib3 + url: https://git.example.com/downstream/lib3 + - name: mainline-app + path: examples/app + url: https://git.example.com/mainline/app + - name: lib2 + path: libraries/lib2 + url: https://git.example.com/mainline/lib2 + +If a whitelist had not been used, the ``lib`` project from the mainline +manifest would have been imported. + +.. _west-manifest-ex3.2: + +Example 3.2: Downstream with path whitelist +------------------------------------------- + +Here is an example showing how to whitelist mainline's libraries only, +using ``path-whitelist``. + +.. code-block:: yaml + + # mainline west.yml: + manifest: + projects: + - name: app + path: examples/app + url: https://git.example.com/mainline/app + - name: lib + path: libraries/lib + url: https://git.example.com/mainline/lib + - name: lib2 + path: libraries/lib2 + url: https://git.example.com/mainline/lib2 + + # downstream west.yml: + manifest: + projects: + - name: mainline + url: https://git.example.com/mainline/manifest + import: + path-whitelist: libraries/* + - name: app + url: https://git.example.com/downstream/app + - name: lib3 + path: libraries/lib3 + url: https://git.example.com/downstream/lib3 + +An equivalent manifest in a single file would be: + +.. code-block:: yaml + + manifest: + projects: + - name: lib + path: libraries/lib + url: https://git.example.com/mainline/lib + - name: lib2 + path: libraries/lib2 + url: https://git.example.com/mainline/lib2 + - name: mainline + url: https://git.example.com/mainline/manifest + - name: app + url: https://git.example.com/downstream/app + - name: lib3 + path: libraries/lib3 + url: https://git.example.com/downstream/lib3 + +.. _west-manifest-ex3.3: + +Example 3.3: Downstream with path blacklist +------------------------------------------- + +Here's an example showing how to blacklist all vendor HALs from mainline by +common path prefix in the installation, add your own version for the chip +you're targeting, and keep everything else. + +.. code-block:: yaml + + # mainline west.yml: + manifest: + defaults: + remote: mainline + remotes: + - name: mainline + url-base: https://git.example.com/mainline + projects: + - name: app + - name: lib + path: libraries/lib + - name: lib2 + path: libraries/lib2 + - name: hal_foo + path: modules/hals/foo + - name: hal_bar + path: modules/hals/bar + - name: hal_baz + path: modules/hals/baz + + # downstream west.yml: + manifest: + projects: + - name: mainline + url: https://git.example.com/mainline/manifest + import: + path-blacklist: modules/hals/* + - name: hal_foo + path: modules/hals/foo + url: https://git.example.com/downstream/hal_foo + +An equivalent manifest in a single file would be: + +.. code-block:: yaml + + manifest: + defaults: + remote: mainline + remotes: + - name: mainline + url-base: https://git.example.com/mainline + projects: + - name: app + - name: lib + path: libraries/lib + - name: lib2 + path: libraries/lib2 + - name: mainline + repo-path: https://git.example.com/mainline/manifest + - name: hal_foo + path: modules/hals/foo + url: https://git.example.com/downstream/hal_foo + +.. _west-manifest-import-seq: + +Option 4: Sequence +================== + +The ``import`` key can also contain a sequence of files, directories, +and mappings. + +.. _west-manifest-ex4.1: + +Example 4.1: Downstream with sequence of manifest files +------------------------------------------------------- + +This example manifest is equivalent to the manifest in +:ref:`west-manifest-ex2.2`, with a sequence of explicitly named files. + +.. code-block:: yaml + + # my-repo/west.yml: + manifest: + projects: + - name: zephyr + url: https://github.com/zephyrproject-rtos/zephyr + import: west.yml + self: + import: + - submanifests/01-libraries.yml + - submanifests/02-vendor-hals.yml + - submanifests/03-applications.yml + +.. _west-manifest-ex4.2: + +Example 4.2: Import order illustration +-------------------------------------- + +This more complicated example shows the order that west imports manifest files: + +.. code-block:: yaml + + # my-repo/west.yml + manifest: + # ... + projects: + - name: my-library + - name: my-app + - name: zephyr + import: true + - name: another-manifest-repo + import: submanifests + self: + import: + - submanifests/libraries.yml + - submanifests/vendor-hals.yml + - submanifests/applications.yml + defaults: + remote: my-remote + +For this example, west resolves imports in this order: + +#. the listed files in :file:`my-repo/submanifests` are first, in the order + they occur (e.g. :file:`libraries.yml` comes before + :file:`applications.yml`, since this is a sequence of files), since the + ``self: import:`` is always imported first +#. :file:`my-repo/west.yml` is next (with projects ``my-library`` etc. as long + as they weren't already defined somewhere in :file:`submanifests`) +#. :file:`zephyr/west.yml` is after that, since that's the first ``import`` key + in the ``projects`` list in :file:`my-repo/west.yml` +#. files in :file:`another-manifest-repo/submanifests` are last (sorted by file + name), since that's the final project ``import`` + +.. _west-manifest-formal: + +Manifest Import Details +======================= + +This section describes how west imports a manifest file a bit more formally. + +Overview +-------- + +A west manifest's ``projects`` and ``self`` sections can have ``import`` keys, +like so: + +.. code-block:: yaml + + # Top-level west.yml. + manifest: + # ... + projects: + - name: foo + revision: rev-1 + import: import-1 + - name: bar + revision: rev-2 + import: import-2 + # ... + - name: baz + revision: rev-N + import: import-N + self: + import: self-import + +Import keys are optional. If any of ``import-1, ..., import-N`` are missing, +west will not import additional manifest data from that project. If +``self-import`` is missing, no additional files in the manifest repository +(beyond the top-level west.yml) are imported. + +The ultimate outcome of resolving manifest imports is a final list of projects, +which is produced by combining the ``projects`` defined in the top-level file +with those defined in imported files. Importing is done in this order: + +#. Manifests from ``self-import`` are imported first. +#. The top-level manifest file's ``projects`` are added in next. +#. Manifests from ``import-1``, ..., ``import-N``, are imported in that order. + +This process recurses if necessary. + +Projects are identified by name. If the same name occurs in multiple manifests, +the first definition is used, and subsequent definitions are ignored. For +example, if ``import-1`` contains a project named ``bar``, that is ignored, +because the top-level :file:`west.yml` has already defined a project by that +name. + +The contents of files named by ``import-1`` through ``import-N`` are imported +from Git at the latest ``manifest-rev`` revisions in their projects. These +revisions can be updated to the values ``rev-1`` through ``rev-N`` by running +``west update``. If any ``manifest-rev`` reference is missing or out of date, +``west update`` also fetches project data from the remote fetch URL and updates +the reference. + +Also note that all imported manifests, from the root manifest to the repository +which defines a project ``P``, must be up to date in order for west to update +``P`` itself. For example, this means ``west update P`` would update +``manifest-rev`` in the ``baz`` project if :file:`baz/west.yml` defines ``P``, +as well as updating the ``manifest-rev`` branch in the local git clone of +``P``. Confusingly, the update of ``baz`` may result in the removal of ``P`` +from :file:`baz/west.yml`, which would cause ``west update P`` to fail with an +unrecognized project! + +For this reason, it's usually best to run plain ``west update`` to avoid errors +if you use manifest imports. By default, west won't fetch any project data over +the network if a project's revision is a SHA or tag which is already available +locally, so updating the extra projects shouldn't take too much time unless +it's really needed. See the documentation for the :ref:`update.fetch +` configuration option for more information. + +If an imported manifest file has a ``west-commands:`` definition in its +``self:`` section, the extension commands defined there are added to the set of +available extensions at the time the manifest is imported. They will thus take +precedence over any extension commands with the same names added later on. + +When an individual ``import`` key refers to multiple manifest files, they are +processed in this order: + +- If the value is a relative path naming a directory (or a map whose ``file`` + is a directory), the manifest files it contains are processed in + lexicographic order -- i.e., sorted by file name. +- If the value is a sequence, its elements are recursively imported in the + order they appear. + .. _west-manifest-cmd: Manifest Command @@ -283,6 +1099,29 @@ It takes an action, and action-specific arguments. The following sections describe each action and provides a basic signature for simple uses. Run ``west manifest --help`` for full details on all options. +.. _west-manifest-resolve: + +Resolving Manifests +=================== + +The ``--resolve`` action outputs a single manifest file equivalent to your +current manifest and all its :ref:`imported manifests `: + +.. code-block:: none + + west manifest --resolve [-o outfile] + +The main use for this action is to see the "final" manifest contents after +performing any ``import``\ s. + +To print detailed information about each imported manifest file and how +projects are handled during manifest resolution, set the maximum verbosity +level using ``-v``: + +.. code-block:: console + + west -v manifest --resolve + Freezing Manifests ================== From 54e9c9bbc58831d6be82c707cdbee0818ad6fd92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 11 Oct 2019 13:51:46 -0700 Subject: [PATCH 060/226] doc: west: 0.7.0 documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reflect changes in the APIs made since 0.6.0. These will also need to be added to the release notes. Some automatic directives weren't generating the desired output, so either do it by hand or let new 0.7.0 docstrings supply the information. Try to better group the content into sections. Signed-off-by: Martí Bolívar --- doc/guides/west/index.rst | 3 +- doc/guides/west/manifest.rst | 24 +++- doc/guides/west/planned.rst | 24 ---- doc/guides/west/release-notes.rst | 78 ++++++++++ doc/guides/west/repo-tool.rst | 22 +-- doc/guides/west/west-apis.rst | 228 ++++++++++++++++++++++-------- 6 files changed, 282 insertions(+), 97 deletions(-) delete mode 100644 doc/guides/west/planned.rst diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index e7828e22..cc6c058d 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -27,7 +27,7 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.6.x`` releases, and provide additional +The following pages document west's ``v0.7.x`` releases, and provide additional context about the tool. .. toctree:: @@ -45,7 +45,6 @@ context about the tool. zephyr-cmds.rst why.rst without-west.rst - planned.rst release-notes.rst For details on west's Python APIs, see :ref:`west-apis`. diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index d0762e90..b7b9b69f 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -89,6 +89,7 @@ top-level ``manifest`` section with some subsections, like this: self: # configuration related to the manifest repository itself, # i.e. the repository containing west.yml (optional) + version: # optional In YAML terms, the manifest file contains a mapping, with a ``manifest`` key. Any other keys and their contents are ignored (west v0.5 also required a @@ -249,7 +250,7 @@ so far using ``defaults`` is: url: https://github.com/user/project-three revision: abcde413a111 -Finally, the ``self`` subsection can be used to control the behavior of the +The ``self`` subsection can be used to control the behavior of the manifest repository itself. Its value is a map with the following keys: - ``path``: Optional. The path to clone the manifest repository into, relative @@ -283,8 +284,27 @@ zephyr repository does contain extension commands, its ``self`` entry declares the location of the corresponding :file:`west-commands.yml` relative to the repository root. +.. _west-manifest-schema-version: + +The ``version`` subsection can be used to mark the lowest version of the +manifest file schema that can parse this file's data: + +.. code-block:: yaml + + manifest: + version: 0.7 + # marks that this manifest uses features available in west 0.7 and + # up, like manifest imports + The pykwalify schema :file:`manifest-schema.yml` in the west source code -repository is used to validate the manifest section. +repository is used to validate the manifest section. The current manifest +``version`` is 0.7, which corresponds to west version 0.7. This is the only +value this field can currently take. + +If a later version of west, say version ``21.0``, includes changes to the +manifest schema that cannot be parsed by west 0.7, then setting ``version: +21.0`` will cause west to print an error when attempting to parse the manifest +data. .. _west-manifest-import: diff --git a/doc/guides/west/planned.rst b/doc/guides/west/planned.rst deleted file mode 100644 index 11d5dcbb..00000000 --- a/doc/guides/west/planned.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. _west-planned-features: - -Planned Features -================ - -Additional west features are under development for future versions of -Zephyr. These include: - -- Multiple manifest files: support for having multiple files which have - manifest data, instead of the single :file:`west.yml` supported today. - See `west #221`_. - -- Toolchain awareness: see `west #180`_. - -See the `west repository issues`_ page for more. - -.. _west #221: - https://github.com/zephyrproject-rtos/west/issues/221 - -.. _west #180: - https://github.com/zephyrproject-rtos/west/issues/180 - -.. _west repository issues: - https://github.com/zephyrproject-rtos/west/issues diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 3d00d7a0..bd705813 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,6 +1,84 @@ West Release Notes ################## +v0.7.0 +****** + +The main user-visible feature in west 0.7 is the :ref:`west-manifest-import` +feature. This allows users to load west manifest data from multiple different +files, resolving the results into a single logical manifest. + +Additional user-visible changes: + +- The idea of a "west installation" has been renamed to "west workspace" in + this documentation and in the west API documentation. The new term seems to + be easier for most people to work with than the old one. +- West manifests now support a :ref:`schema version + `. +- The "west config" command can now be run outside of a workspace, e.g. + to run ``west config --global section.key value`` to set a configuration + option's value globally. +- There is a new :ref:`west topdir ` command, which + prints the root directory of the current west workspace. +- The ``west -vv init`` command now prints the git operations being performed, + and their results. +- The restriction that no project can be named "manifest" is now enforced; the + name "manifest" is reserved for the manifest repository, and is usable as + such in commands like ``west list manifest``, instead of ``west list + path-to-manifest-repository`` being the only way to say that +- It's no longer an error if there is no project named "zephyr". This is + part of an effort to make west generally usable for non-Zephyr use cases. +- Various bug fixes. + +The developer-visible changes to the :ref:`west-apis` are: + +- west.build and west.cmake: deprecated; this is Zephyr-specific functionality + and should never have been part of west. Since Zephyr v1.14 LTS relies on it, + it will continue to be included in the distribution, but will be removed + when that version of Zephyr is obsoleted. +- west.commands: + + - WestCommand.requires_installation: deprecated; use requires_workspace instead + - WestCommand.requires_workspace: new + - WestCommand.has_manifest: new + - WestCommand.manifest: this is now settable +- west.configuration: callers can now identify the workspace directory + when reading and writing configuration files +- west.log: + + - msg(): new +- west.manifest: + + - The module now uses the standard logging module instead of west.log + - QUAL_REFS_WEST: new + - SCHEMA_VERSION: new + - Defaults: removed + - Manifest.as_dict(): new + - Manifest.as_frozen_yaml(): new + - Manifest.as_yaml(): new + - Manifest.from_file() and from_data(): these factory methods are more + flexible to use and less reliant on global state + - Manifest.validate(): new + - ManifestImportFailed: new + - ManifestProject: semi-deprecated and will likely be removed later. + - Project: the constructor now takes a topdir argument + - Project.format() and its callers are removed. Use f-strings instead. + - Project.name_and_path: new + - Project.remote_name: new + - Project.sha() now captures stderr + - Remote: removed + +West now requires Python 3.6 or later. Additionally, some features may rely on +Python dictionaries being insertion-ordered; this is only an implementation +detail in CPython 3.6, but is is part of the language specification as of +Python 3.7. + +v0.6.3 +****** + +This point release fixes an error in the behavior of the deprecated +``west.cmake`` module. + v0.6.2 ****** diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 2e06c37e..84216788 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -262,6 +262,17 @@ Miscellaneous Commands West has a few more commands for managing the multi-repo, which are briefly discussed here. Run ``west -h`` for detailed help. +- ``west forall -c COMMAND [PROJECT ...]``: Runs the shell command ``COMMAND`` + within the top-level repository directory of each of the specified projects + (default: all cloned projects). If ``COMMAND`` consists of more than one + word, it must be quoted to prevent it from being split up by the shell. + + To run an arbitrary Git command in each project, use something like ``west + forall -c 'git --options'``. Note that ``west forall`` can be used + to run any command, though, not just Git commands. + +- ``west help ``: this is equivalent to ``west -h``. + - ``west list [-f FORMAT] [PROJECT ...]``: Lists project information from the manifest file, such as URL, revision, path, etc. The printed information can be controlled using the ``-f`` option. @@ -278,16 +289,7 @@ discussed here. Run ``west -h`` for detailed help. - ``west status [PROJECT ...]``: Like ``west diff``, for running ``git status``. -- ``west forall -c COMMAND [PROJECT ...]``: Runs the shell command ``COMMAND`` - within the top-level repository directory of each of the specified projects - (default: all cloned projects). If ``COMMAND`` consists of more than one - word, it must be quoted to prevent it from being split up by the shell. - - To run an arbitrary Git command in each project, use something like ``west - forall -c 'git --options'``. Note that ``west forall`` can be used - to run any command, though, not just Git commands. - -- ``west help ``: this is equivalent to ``west -h``. +- ``west topdir``: Prints the top directory of the west workspace. .. _PyPI: https://pypi.org/project/west/ diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index b474edfa..41328d1c 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -15,6 +15,8 @@ the zephyr repository. These APIs should be considered unstable until west version 1.0 (see `west #38`_). +.. _west #38: + https://github.com/zephyrproject-rtos/west/issues/38 **Contents**: @@ -37,28 +39,10 @@ All built-in and extension commands are implemented as subclasses of the :py:class:`WestCommand` class defined here. Some exception types are also provided. -.. py:class:: west.commands.WestCommand - - .. automethod:: __init__ - - .. versionadded:: 0.6.0 - The *requires_installation* parameter. - - Methods: - - .. automethod:: run - - .. versionchanged:: 0.6.0 - The *topdir* argument was added. - - .. automethod:: add_parser - - All subclasses must provide the following abstract methods, which are used - to implement the above: - - .. automethod:: do_add_parser +WestCommand +=========== - .. automethod:: do_run +.. py:class:: west.commands.WestCommand Instance attributes: @@ -78,10 +62,12 @@ provided. As passed to the constructor. - .. py:attribute:: requires_installation + .. py:attribute:: requires_workspace As passed to the constructor. + .. versionadded:: 0.7.0 + .. py:attribute:: parser The argument parser created by calling ``WestCommand.add_parser()``. @@ -90,11 +76,46 @@ provided. .. py:attribute:: manifest - A read-only property which returns the :py:class:`west.manifest.Manifest` + A property which returns the :py:class:`west.manifest.Manifest` instance for the current manifest file or aborts the program if one was not provided. This is only safe to use from the ``do_run()`` method. .. versionadded:: 0.6.1 + .. versionchanged:: 0.7.0 + This is now settable. + + .. py:attribute:: has_manifest + + True if reading the manifest property will succeed instead of erroring + out. + + Constructor: + + .. automethod:: __init__ + + .. versionadded:: 0.6.0 + The *requires_installation* parameter. + .. versionadded:: 0.7.0 + The *requires_workspace* parameter. + + Methods: + + .. automethod:: run + + .. versionchanged:: 0.6.0 + The *topdir* argument was added. + + .. automethod:: add_parser + + All subclasses must provide the following abstract methods, which are used + to implement the above: + + .. automethod:: do_add_parser + + .. automethod:: do_run + +Exceptions +========== .. autoclass:: west.commands.CommandError :show-inheritance: @@ -106,18 +127,6 @@ provided. .. autoclass:: west.commands.CommandContextError :show-inheritance: -.. autoclass:: west.commands.ExtensionCommandError - :show-inheritance: - - .. py:method:: ExtensionCommandError.__init__(hint=None, **kwargs) - - If *hint* is given, it is a string indicating the cause of the problem. - All other kwargs are passed to the super constructor. - - .. py:attribute:: hint - - As passed to the constructor. - .. _west-apis-configuration: west.configuration @@ -125,7 +134,10 @@ west.configuration .. automodule:: west.configuration -.. autoclass:: west.configuration.ConfigFile +This provides API access to west configuration files and data. + +Reading and writing options +=========================== .. autofunction:: west.configuration.read_config @@ -134,6 +146,11 @@ west.configuration .. autofunction:: west.configuration.update_config +.. autoclass:: west.configuration.ConfigFile + +Global configuration instance +============================= + .. py:data:: west.configuration.config Module-global ConfigParser instance for the current configuration. This @@ -146,7 +163,42 @@ west.log ******** .. automodule:: west.log - :members: set_verbosity, VERBOSE_NONE, VERBOSE_NORMAL, VERBOSE_VERY, VERBOSE_EXTREME, dbg, inf, wrn, err, die, banner, small_banner + +This module's functions are used whenever a running west command needs to print +to standard out or error streams. + +This is safe to use from extension commands if you want output that mirrors +that of west itself. + +Verbosity control +================= + +To set the global verbosity level, use ``set_verbosity()``. + +.. autofunction:: set_verbosity + +These verbosity levels are defined. + +.. autodata:: VERBOSE_NONE +.. autodata:: VERBOSE_NORMAL +.. autodata:: VERBOSE_VERY +.. autodata:: VERBOSE_EXTREME + +Output functions +================ + +The main functions are ``dbg()``, ``inf()``, ``wrn()``, ``err()``, and +``die()``. Two special cases of ``inf()``, ``banner()`` and ``small_banner()``, +are also available for grouping output into "sections". + +.. autofunction:: dbg +.. autofunction:: inf +.. autofunction:: wrn +.. autofunction:: err +.. autofunction:: die + +.. autofunction:: banner +.. autofunction:: small_banner .. _west-apis-manifest: @@ -155,75 +207,130 @@ west.manifest .. automodule:: west.manifest -.. autodata:: MANIFEST_PROJECT_INDEX +The main classes are `Manifest` and `Project`. These represent the contents of +a :ref:`manifest file `. The recommended methods for parsing +west manifests are `Manifest.from_file` and `Manifest.from_data`. -.. autodata:: MANIFEST_REV_BRANCH +Constants and functions +======================= +.. autodata:: MANIFEST_PROJECT_INDEX +.. autodata:: MANIFEST_REV_BRANCH .. autodata:: QUAL_MANIFEST_REV_BRANCH +.. autodata:: QUAL_REFS_WEST +.. autodata:: SCHEMA_VERSION .. autofunction:: west.manifest.manifest_path +.. autofunction:: west.manifest.validate + +Manifest and sub-objects +======================== + .. autoclass:: west.manifest.Manifest + .. automethod:: __init__ + .. versionchanged:: 0.7.0 + The ``importer`` and ``import_flags`` keyword arguments. + .. automethod:: from_file + .. versionchanged:: 0.7.0 + ``**kwargs`` added. .. automethod:: from_data + .. versionchanged:: 0.7.0 + ``**kwargs`` added, and ``source_data`` may be a ``str``. - .. automethod:: __init__ - - .. automethod:: get_remote + Conveniences for accessing sub-objects by name or other identifier: .. automethod:: get_projects - .. versionadded:: 0.6.1 - .. automethod:: as_frozen_dict + Additional methods: -.. autoclass:: west.manifest.Defaults - :members: - :member-order: groupwise + .. automethod:: as_dict + .. versionadded:: 0.7.0 + .. automethod:: as_frozen_dict + .. automethod:: as_yaml + .. versionadded:: 0.7.0 + .. automethod:: as_frozen_yaml + .. versionadded:: 0.7.0 -.. autoclass:: west.manifest.Remote - :members: - :member-order: groupwise +.. autoclass:: west.manifest.ImportFlag .. autoclass:: west.manifest.Project + .. (note: attributes are part of the class docstring) + + .. versionchanged:: 0.7.0 + The ``remote`` attribute was removed. Its semantics could no longer + be preserved when support for manifest ``import`` keys was added. + + .. versionadded:: 0.7.0 + The ``remote_name`` and ``name_and_path`` attributes. + + Constructor: + .. automethod:: __init__ - .. automethod:: as_dict + .. versionchanged:: 0.7.0 + The parameters were incompatibly changed from previous versions. - .. automethod:: format + Methods: - .. automethod:: git + .. automethod:: as_dict + .. versionadded:: 0.7.0 + .. automethod:: git .. versionchanged:: 0.6.1 The ``capture_stderr`` kwarg. + .. versionchanged:: 0.7.0 + The (now removed) ``Project.format`` method is no longer called on + arguments. .. automethod:: sha + .. versionchanged:: 0.7.0 + Standard error is now captured. .. automethod:: is_ancestor_of .. automethod:: is_cloned - .. versionadded:: 0.6.1 .. automethod:: is_up_to_date_with .. automethod:: is_up_to_date + .. automethod:: read_at + .. versionadded:: 0.7.0 + + .. automethod:: listdir_at + .. versionadded:: 0.7.0 + .. autoclass:: west.manifest.ManifestProject - :members: - :member-order: groupwise + + A limited subset of Project methods is supported. + Results for calling others are not specified. + + .. automethod:: as_dict .. versionadded:: 0.6.0 +Exceptions +========== + .. autoclass:: west.manifest.MalformedManifest :show-inheritance: .. autoclass:: west.manifest.MalformedConfig :show-inheritance: +.. autoclass:: west.manifest.ManifestVersionError + :show-inheritance: + +.. autoclass:: west.manifest.ManifestImportFailed + :show-inheritance: + .. _west-apis-util: west.util @@ -233,12 +340,15 @@ west.util .. automodule:: west.util +Functions +========= + .. autofunction:: west.util.west_dir .. autofunction:: west.util.west_topdir +Exceptions +========== + .. autoclass:: west.util.WestNotFound :show-inheritance: - -.. _west #38: - https://github.com/zephyrproject-rtos/west/issues/38 From 9163bb0b439ce35933f576763f0b742d7ebc0d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 18 Feb 2020 14:05:58 -0800 Subject: [PATCH 061/226] doc: split devicetree docs into multiple pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The one page on devicetree is too long. Split it into multiple pages to make it easier to digest and more squintable. This is basically just moving content around; minimal changes have been made apart from redoing some transitions and adding a couple of introductory paragraphs. Rename the 'device-tree' Sphinx :ref: target while we are here. Signed-off-by: Martí Bolívar --- doc/guides/west/build-flash-debug.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 070e5e0e..0fae8fcc 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -203,7 +203,7 @@ are given. All command-line arguments to ``west build`` after a ``--`` are passed to CMake. To set :ref:`DTC_OVERLAY_FILE ` to :file:`enable-modem.overlay`, -using that file as a :ref:`devicetree overlay `:: +using that file as a :ref:`devicetree overlay `:: west build -b reel_board -- -DDTC_OVERLAY_FILE=enable-modem.overlay From a45e58dab37ccd5006241f9b45bb9afcb089d737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 24 Feb 2020 15:01:25 -0800 Subject: [PATCH 062/226] doc: west: add examples for each topology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add example west.yml files showing how to build west workspaces of each type. Split these into separate sections as a result since they're longer. Signed-off-by: Martí Bolívar --- doc/guides/west/repo-tool.rst | 224 ++++++++++++++++++++++++---------- 1 file changed, 160 insertions(+), 64 deletions(-) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 84216788..ca581824 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -78,70 +78,166 @@ repository. Topologies supported ******************** -The following three source code topologies supported by west: - -* **T1**: Star topology with zephyr as the manifest repository: - - - The zephyr repository acts as the central repository and includes a - complete list of projects used upstream - - Default (upstream) configuration - - Analogy with existing mechanisms: Git sub-modules with zephyr as the - super-project - - See :ref:`west-installation` for how mainline Zephyr is an example - of this topology - -* **T2**: Star topology with an application repository as the manifest - repository: - - - A repository containing a Zephyr application acts as the central repository - and includes a complete list of other projects, including the zephyr - repository, required to build it - - Useful for those focused on a single application - - Analogy with existing mechanisms: Git sub-modules with the application as - the super-project, zephyr and other projects as sub-modules - - An installation using this topology could look like this: - - .. code-block:: none - - app-manifest-installation - ├── application - │   ├── CMakeLists.txt - │   ├── prj.conf - │   ├── src - │   │   └── main.c - │   └── west.yml - ├── modules - │   └── lib - │   └── tinycbor - └── zephyr - -* **T3**: Forest topology: - - - A dedicated manifest repository which contains no Zephyr source code, - and specifies a list of projects all at the same "level" - - Useful for downstream distributions with no "central" repository - - Analogy with existing mechanisms: Google repo-based source distribution - - An installation using this topology could look like this: - - .. code-block:: none - - forest - ├── app1 - │   ├── CMakeLists.txt - │   ├── prj.conf - │   └── src - │   └── main.c - ├── app2 - │   ├── CMakeLists.txt - │   ├── prj.conf - │   └── src - │   └── main.c - ├── manifest-repo - │   └── west.yml - ├── modules - │   └── lib - │   └── tinycbor - └── zephyr +The following are example source code topologies supported by west. + +- T1: star topology, zephyr is the manifest repository +- T2: star topology, a Zephyr application is the manifest repository +- T3: forest topology, freestanding manifest repository + +T1: Star topology, zephyr is the manifest repository +==================================================== + +- The zephyr repository acts as the central repository and specifies + its :ref:`modules` in its :file:`west.yml` +- Analogy with existing mechanisms: Git submodules with zephyr as the + super-project + +This is the default. See :ref:`west-installation` for how mainline Zephyr is an +example of this topology. + +.. _west-t2: + +T2: Star topology, application is the manifest repository +========================================================= + +- Useful for those focused on a single application +- A repository containing a Zephyr application acts as the central repository + and names other projects required to build it in its :file:`west.yml`. This + includes the zephyr repository and any modules. +- Analogy with existing mechanisms: Git submodules with the application as + the super-project, zephyr and other projects as submodules + +An installation using this topology looks like this: + +.. code-block:: none + + west-workspace + ├── application + │   ├── CMakeLists.txt + │   ├── prj.conf + │   ├── src + │   │   └── main.c + │   └── west.yml + ├── modules + │   └── lib + │   └── tinycbor + └── zephyr + +Here is an example :file:`application/west.yml` which uses +:ref:`west-manifest-import`, available since west 0.7, to import Zephyr v2.2.0 +and its modules into the application manifest file: + +.. code-block:: yaml + + # Example T2 west.yml, using manifest imports. + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v2.2.0 + import: true + self: + path: application + +You can still selectively "override" individual Zephyr modules if you use +``import:`` in this way; see :ref:`west-manifest-ex1.3` for an example. + +Another way to do the same thing is to copy/paste :file:`zephyr/west.yml` +to :file:`application/west.yml`, adding an entry for the zephyr +project itself, like this: + +.. code-block:: yaml + + # Equivalent to the above, but with manually maintained Zephyr modules. + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + defaults: + remote: zephyrproject-rtos + projects: + - name: zephyr + revision: v2.2.0 + west-commands: scripts/west-commands.yml + - name: net-tools + revision: some-sha-goes-here + path: tools/net-tools + # ... other Zephyr modules go here ... + self: + path: application + +(The ``west-commands`` is there for :ref:`west-build-flash-debug` and other +Zephyr-specific :ref:`west-extensions`. It's not necessary when using +``import``.) + +The main advantage to using ``import`` is not having to track the revisions of +imported projects separately. In the above example, using ``import`` means +Zephyr's :ref:`module ` versions are automatically determined from the +:file:`zephyr/west.yml` revision, instead of having to be copy/pasted (and +maintained) on their own. + +T3: Forest topology +=================== + +- Useful for those supporting multiple independent applications or downstream + distributions with no "central" repository +- A dedicated manifest repository which contains no Zephyr source code, + and specifies a list of projects all at the same "level" +- Analogy with existing mechanisms: Google repo-based source distribution + +An installation using this topology looks like this: + +.. code-block:: none + + west-workspace + ├── app1 + │   ├── CMakeLists.txt + │   ├── prj.conf + │   └── src + │   └── main.c + ├── app2 + │   ├── CMakeLists.txt + │   ├── prj.conf + │   └── src + │   └── main.c + ├── manifest-repo + │   └── west.yml + ├── modules + │   └── lib + │   └── tinycbor + └── zephyr + +Here is an example T3 :file:`manifest-repo/west.yml` which uses +:ref:`west-manifest-import`, available since west 0.7, to import Zephyr +v2.2.0 and its modules, then add the ``app1`` and ``app2`` projects: + +.. code-block:: yaml + + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + - name: your-git-server + url-base: https://git.example.com/your-company + defaults: + remote: your-git-server + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v2.2.0 + import: true + - name: app1 + revision: SOME_SHA_OR_BRANCH_OR_TAG + - name: app2 + revision: ANOTHER_SHA_OR_BRANCH_OR_TAG + self: + path: manifest-repo + +You can also do this "by hand" by copy/pasting :file:`zephyr/west.yml` +as shown :ref:`above ` for the T2 topology, with the same caveats. .. _west-struct: From cb546e79c8ab0aa630dff3a0a8ff60a5c6d53e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 24 Feb 2020 15:01:57 -0800 Subject: [PATCH 063/226] doc: west: update structure page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main change is that west 0.7 is not a namespace package anymore. Make some other improvements while here. Signed-off-by: Martí Bolívar --- doc/guides/west/repo-tool.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index ca581824..53816b0c 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -244,12 +244,14 @@ as shown :ref:`above ` for the T2 topology, with the same caveats. West Structure ************** -West's code is distributed via PyPI in a `namespace package`_ named ``west``. -See :ref:`west-apis` for API documentation. - -This distribution also includes a launcher executable, also named ``west``. When -west is installed, the launcher is placed by :file:`pip3` somewhere in the -user's ``PATH``. This is the command-line entry point. +West's code is distributed via PyPI in a Python package named ``west``. See +:ref:`west-apis` for API documentation. + +This distribution also includes a launcher executable, also named ``west``. +When west is installed, the launcher is placed by :file:`pip3` somewhere in the +user's filesystem (exactly where depends on the operating system, but should be +on the ``PATH`` :ref:`environment variable `). This launcher is the +command-line entry point. .. _west-manifest-rev: From 1e662b28f424cf5c3f2e44534c5d990aee4ff88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 24 Feb 2020 15:08:00 -0800 Subject: [PATCH 064/226] doc: west: 'west installation' is now 'west workspace' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This nomenclature change was done in west 0.7 because it seems to be a lot easier for people to understand. Propagate it to all the west documentation. Signed-off-by: Martí Bolívar --- doc/guides/west/config.rst | 14 +++++----- doc/guides/west/extensions.rst | 3 +- doc/guides/west/manifest.rst | 22 +++++++-------- doc/guides/west/moving-to-west.rst | 4 +-- doc/guides/west/repo-tool.rst | 43 +++++++++++++++-------------- doc/guides/west/troubleshooting.rst | 17 ++++++------ doc/guides/west/without-west.rst | 2 +- 7 files changed, 54 insertions(+), 51 deletions(-) diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index 9b87b0a0..5a9ee86d 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -45,12 +45,12 @@ There are three types of configuration file: combination of :envvar:`%HOMEDRIVE%` and :envvar:`%HOMEPATH%`. 3. **Local**: Settings in this file affect west's behavior for the - current :term:`west installation`. The file is :file:`.west/config`, relative - to the installation's root directory. + current :term:`west workspace`. The file is :file:`.west/config`, relative + to the workspace's root directory. A setting in a file which appears lower down on this list overrides an earlier setting. For example, if ``color.ui`` is ``true`` in the system's configuration -file, but ``false`` in the installation's, then the final value is +file, but ``false`` in the workspace's, then the final value is ``false``. Similarly, settings in the user configuration file override system settings, and so on. @@ -76,11 +76,11 @@ To set ``manifest.path`` to :file:`some-other-manifest`: Doing the above means that commands like ``west update`` will look for the :term:`west manifest` inside the :file:`some-other-manifest` directory -(relative to the installation root directory) instead of the directory given to +(relative to the workspace root directory) instead of the directory given to ``west init``, so be careful! To read ``zephyr.base``, the value which will be used as ``ZEPHYR_BASE`` if it -is unset in the calling environment (also relative to the installation root): +is unset in the calling environment (also relative to the workspace root): .. code-block:: console @@ -101,7 +101,7 @@ zephyr``.) To set ``color.ui`` to ``false`` in the global (user-wide) configuration file, so that west will no longer print colored output for that user when run in any -installation: +workspace: .. code-block:: console @@ -136,7 +136,7 @@ commands are documented in the pages for those commands. * - ``commands.allow_extensions`` - Boolean, default ``true``, disables :ref:`west-extensions` if ``false`` * - ``manifest.path`` - - String, relative path from the :term:`west installation` root directory + - String, relative path from the :term:`west workspace` root directory to the manifest repository used by ``west update`` and other commands which parse the manifest. Set locally by ``west init``. * - ``update.fetch`` diff --git a/doc/guides/west/extensions.rst b/doc/guides/west/extensions.rst index 00a29c35..fe4fc8f8 100644 --- a/doc/guides/west/extensions.rst +++ b/doc/guides/west/extensions.rst @@ -41,7 +41,8 @@ globally for whenever you run west, use: west config --global commands.allow_extensions false -If you want to, you can then re-enable them in a particular installation with: +If you want to, you can then re-enable them in a particular :term:`west +workspace` with: .. code-block:: console diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index b7b9b69f..08dcb970 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -18,7 +18,7 @@ introduction and command overview, see :ref:`west-multi-repo`. Multiple Repository Model ************************* -West's view of the repositories in a :term:`west installation`, and their +West's view of the repositories in a :term:`west workspace`, and their history, looks like the following figure (though some parts of this example are specific to upstream Zephyr's use of west): @@ -32,7 +32,7 @@ specific to upstream Zephyr's use of west): The history of the manifest repository is the line of Git commits which is "floating" on top of the gray plane. Parent commits point to child commits using solid arrows. The plane below contains the Git commit history of the -repositories in the installation, with each project repository boxed in by a +repositories in the workspace, with each project repository boxed in by a rectangle. Parent/child commit relationships in each repository are also shown with solid arrows. @@ -124,7 +124,7 @@ example, you might use ``git@example.com:base1`` if ``remote1`` supported Git over SSH as well. Anything acceptable to Git will work. The ``projects`` subsection contains a sequence describing the project -repositories in the west installation. Every project has a unique name. You can +repositories in the west workspace. Every project has a unique name. You can specify what Git remote URLs to use when cloning and fetching the projects, what revisions to track, and where the project should be stored on the local file system. @@ -157,7 +157,7 @@ In this manifest: with a ``/`` and the project ``name`` to form the URL. Locally, this project will be cloned at path ``extra/project-1`` relative to - the west installation's root directory, since it has an explicit ``path`` + the west workspace's root directory, since it has an explicit ``path`` attribute with this value. Since the project has no ``revision`` specified, ``master`` is used by @@ -208,7 +208,7 @@ The list of project keys and their usage follows. Sometimes we'll refer to the A project revision can be a branch, tag, or SHA. The default ``revision`` is ``master`` if not otherwise specified. - ``path``: Optional. Relative path specifying where to clone the repository - locally, relative to the top directory in the west installation. If missing, + locally, relative to the top directory in the west workspace. If missing, the project's ``name`` is used as a directory name. - ``clone-depth``: Optional. If given, a positive integer which creates a shallow history in the cloned repository limited to the given number of @@ -254,7 +254,7 @@ The ``self`` subsection can be used to control the behavior of the manifest repository itself. Its value is a map with the following keys: - ``path``: Optional. The path to clone the manifest repository into, relative - to the west installation's root directory. If not given, the basename of the + to the west workspace's root directory. If not given, the basename of the path component in the manifest repository URL will be used by default. For example, if the URL is ``https://git.example.com/project-repo``, the manifest repository would be cloned to the directory :file:`project-repo`. @@ -411,7 +411,7 @@ You have a source code repository you want to use with Zephyr v1.14.1 LTS. You want to maintain the whole thing using west. You don't want to modify any of the mainline repositories. -In other words, the west installation you want looks like this: +In other words, the west workspace you want looks like this: .. code-block:: none @@ -441,7 +441,7 @@ You can do this with the following :file:`my-repo/west.yml`: revision: v1.14.1 import: true -You can then create the installation on your computer like this, assuming +You can then create the workspace on your computer like this, assuming ``my-repo`` is hosted at ``https://git.example.com/my-repo``: .. code-block:: console @@ -480,7 +480,7 @@ master`` for the zephyr repository: revision: master import: true -You can create the installation in the same way: +You can create the workspace in the same way: .. code-block:: console @@ -711,7 +711,7 @@ Example 2.3: Continuous Integration overrides --------------------------------------------- Your continuous integration system needs to fetch and test multiple -repositories in your west installation from a developer's forks instead of your +repositories in your west workspace from a developer's forks instead of your mainline development trees, to see if the changes all work well together. Starting with :ref:`west-manifest-ex2.2`, the CI scripts add a @@ -890,7 +890,7 @@ Example 3.3: Downstream with path blacklist ------------------------------------------- Here's an example showing how to blacklist all vendor HALs from mainline by -common path prefix in the installation, add your own version for the chip +common path prefix in the workspace, add your own version for the chip you're targeting, and keep everything else. .. code-block:: yaml diff --git a/doc/guides/west/moving-to-west.rst b/doc/guides/west/moving-to-west.rst index 51e8d449..d79ba199 100644 --- a/doc/guides/west/moving-to-west.rst +++ b/doc/guides/west/moving-to-west.rst @@ -37,13 +37,13 @@ instead. See :ref:`west-troubleshooting` for advice on common issues. The name :file:`zephyrproject` is recommended, but you can choose any name with no spaces anywhere in the path. -#. Create a :ref:`west installation ` using the zephyr +#. Create a :ref:`west workspace ` using the zephyr repository as a local manifest repository:: west init -l zephyr This creates :file:`zephyrproject/.west`, marking the root of your - installation, and does some other setup. It will not change the contents of + workspace, and does some other setup. It will not change the contents of the zephyr repository in any way. #. Clone the rest of the repositories used by zephyr:: diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 53816b0c..69ca1592 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -14,19 +14,20 @@ rationale, and motivation. multi-repo work, not to replace it. For tasks that only operate on one repository, just use plain Git commands. -.. _west-installation: +.. _west-workspace: Introduction ************ West's built-in commands allow you to work with projects composed of multiple Git repositories installed under a common parent directory, which we call a -*west installation*. This works similarly to `Git Submodules +*west workspace* (before west 0.7, this was called a *west installation*). This +works similarly to `Git Submodules `_ and Google's `repo `_. -A west installation is the result of running the ``west init`` command, which -is described in more detail below. For upstream Zephyr, the installation looks +A west workspace is the result of running the ``west init`` command, which +is described in more detail below. For upstream Zephyr, the workspace looks like this: .. code-block:: none @@ -43,34 +44,34 @@ like this: ├── net-tools └── [ ... other projects ...] -Above, :file:`zephyrproject` is the name of the west installation's root +Above, :file:`zephyrproject` is the name of the west workspace's root directory. This name is just an example -- it could be anything, like ``z``, -``my-zephyr-installation``, etc. The file :file:`.west/config` is the -installation's :ref:`local configuration file `. +``my-zephyr-workspace``, etc. The file :file:`.west/config` is the +workspace's :ref:`local configuration file `. -Every west installation contains exactly one *manifest repository*, which is a +Every west workspace contains exactly one *manifest repository*, which is a Git repository containing a file named :file:`west.yml`, which is the *west manifest*. The location of the manifest repository is given by the :ref:`manifest.path configuration option ` in the local configuration file. The manifest file, along with west's configuration files, -controls the installation's behavior. For upstream Zephyr, :file:`zephyr` is +controls the workspace's behavior. For upstream Zephyr, :file:`zephyr` is the manifest repository, but you can configure west to use any Git repository -in the installation as the manifest repository. The only requirement is that it +in the workspace as the manifest repository. The only requirement is that it contains a valid manifest file. See :ref:`west-manifests` for more details on what this means. Both of the :file:`tinycbor` and :file:`net-tools` directories are *projects* -managed by west, and configured in the manifest file. A west installation can +managed by west, and configured in the manifest file. A west workspace can contain arbitrarily many projects. As shown above, projects can be located -anywhere in the installation. They don't have to be subdirectories of the +anywhere in the workspace. They don't have to be subdirectories of the manifest directory, and they can be inside of arbitrary subdirectories inside -the installation's root directory. By default, the Zephyr build system uses -west to get the locations of all the projects in the installation, so any code +the workspace's root directory. By default, the Zephyr build system uses +west to get the locations of all the projects in the workspace, so any code they contain can be used by applications. This behavior can be overridden using the ``ZEPHYR_MODULES`` CMake variable; see :zephyr_file:`cmake/zephyr_module.cmake` for details. -Finally, any repository managed by a west installation can contain +Finally, any repository managed by a west workspace can contain :ref:`extension commands `, which are extra west commands provided by that project. This includes the manifest repository and any project repository. @@ -92,7 +93,7 @@ T1: Star topology, zephyr is the manifest repository - Analogy with existing mechanisms: Git submodules with zephyr as the super-project -This is the default. See :ref:`west-installation` for how mainline Zephyr is an +This is the default. See :ref:`west-workspace` for how mainline Zephyr is an example of this topology. .. _west-t2: @@ -107,7 +108,7 @@ T2: Star topology, application is the manifest repository - Analogy with existing mechanisms: Git submodules with the application as the super-project, zephyr and other projects as submodules -An installation using this topology looks like this: +A workspace using this topology looks like this: .. code-block:: none @@ -188,7 +189,7 @@ T3: Forest topology and specifies a list of projects all at the same "level" - Analogy with existing mechanisms: Google repo-based source distribution -An installation using this topology looks like this: +A workspace using this topology looks like this: .. code-block:: none @@ -303,7 +304,7 @@ The ``west init`` and ``west update`` multi-repo commands are the most important to understand. - ``west init [-l] [-m URL] [--mr REVISION] [PATH]``: create a west - installation in directory :file:`PATH` (i.e. :file:`.west` etc. will be + workspace in directory :file:`PATH` (i.e. :file:`.west` etc. will be created there). If the ``PATH`` argument is not given, the current working directory is used. This command does not clone any of the projects in the manifest; that is done the next time ``west update`` is run. @@ -311,11 +312,11 @@ important to understand. This command can be invoked in two ways: 1. If you already have a local clone of the zephyr repository and want to - create a west installation around it, you can use the ``-l`` switch to + create a west workspace around it, you can use the ``-l`` switch to pass its path to west, as in: ``west init -l path/to/zephyr``. This is the only reason to use ``-l``. - 2. Otherwise, omit ``-l`` to create a new installation from a remote manifest + 2. Otherwise, omit ``-l`` to create a new workspace from a remote manifest repository. You can give the manifest URL using the ``-m`` switch, and its revision using ``--mr``. For example, invoking west with: ``west init -m https://github.com/zephyrproject-rtos/zephyr --mr v1.15.0`` would clone diff --git a/doc/guides/west/troubleshooting.rst b/doc/guides/west/troubleshooting.rst index 1f1fdc21..fc2e31d4 100644 --- a/doc/guides/west/troubleshooting.rst +++ b/doc/guides/west/troubleshooting.rst @@ -16,8 +16,8 @@ If you see this error when running ``west init``: (choose from 'init', 'update', 'list', 'manifest', 'diff', 'status', 'forall', 'config', 'selfupdate', 'help') -Then you have an old version of west installed, and are trying to use it in an -installation that requires a more recent version. +Then you have an old version of west installed, and are trying to use it in a +workspace that requires a more recent version. The easiest way to resolve this issue is to upgrade west and retry as follows: @@ -29,23 +29,24 @@ The easiest way to resolve this issue is to upgrade west and retry as follows: this step.) #. Completely remove the :file:`zephyrproject/.west` directory (if you don't, - you will get the "already in an installation" error message discussed next). + you will get the "already in a workspace" error message discussed next). #. Run ``west init`` again. "already in an installation" **************************** -You may see this error when running ``west init``: +You may see this error when running ``west init`` with west 0.6: .. code-block:: none FATAL ERROR: already in an installation (), aborting -If this is unexpected and you're really trying to create a new installation, +If this is unexpected and you're really trying to create a new west workspace, then it's likely that west is using the :envvar:`ZEPHYR_BASE` :ref:`environment -variable ` to locate a west installation elsewhere on your system. -This is intentional behavior; it allows you to put your Zephyr applications in -any directory and still use west. +variable ` to locate a workspace elsewhere on your system. + +This is intentional; it allows you to put your Zephyr applications in +any directory and still use west to build, flash, and debug them, for example. To resolve this issue, unset :envvar:`ZEPHYR_BASE` and try again. diff --git a/doc/guides/west/without-west.rst b/doc/guides/west/without-west.rst index 467f532f..7078578f 100644 --- a/doc/guides/west/without-west.rst +++ b/doc/guides/west/without-west.rst @@ -71,7 +71,7 @@ west commands wrap). If you want to use these build system targets but do not want to install west on your system using ``pip``, it is possible to do so -by manually creating a :term:`west installation`: +by manually creating a :term:`west workspace`: .. code-block:: console From 6101d3f516fb80e1bc4297aff3891a3f59fec7d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 4 Mar 2020 11:38:33 -0800 Subject: [PATCH 065/226] doc: more board porting improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Incorporate more feedback suggested in #23080. Suggested-by: Lucian Copeland Signed-off-by: Martí Bolívar --- doc/guides/west/build-flash-debug.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 0fae8fcc..2161d326 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -532,8 +532,8 @@ For example, to print usage information about the ``jlink`` runner:: .. _west-runner: -Implementation Details -********************** +runners package API +******************* The flash and debug commands are implemented as west *extension commands*: that is, they are west commands whose source code lives From f75dfa63abf606993cb7957439a736f9224b6fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 10 Mar 2020 18:16:25 -0700 Subject: [PATCH 066/226] doc: dts: revisit documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is joint work with Kumar Gala (see signed-off-by). Document the changes to the generated node macros in macros.bnf, moving the old file to legacy-macros.bnf and putting it in its own section. The actual generated macros are now a low-level detail, so rewrite the foregoing sections as examples in terms of the new APIs. Signed-off-by: Martí Bolívar Signed-off-by: Kumar Gala --- doc/guides/west/build-flash-debug.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 2161d326..04a59710 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -202,8 +202,11 @@ Notice how the ``--`` only appears once, even though multiple CMake arguments are given. All command-line arguments to ``west build`` after a ``--`` are passed to CMake. -To set :ref:`DTC_OVERLAY_FILE ` to :file:`enable-modem.overlay`, -using that file as a :ref:`devicetree overlay `:: +.. _west-building-dtc-overlay-file: + +To set :ref:`DTC_OVERLAY_FILE ` to +:file:`enable-modem.overlay`, using that file as a +:ref:`devicetree overlay `:: west build -b reel_board -- -DDTC_OVERLAY_FILE=enable-modem.overlay From 7da6475d36deb3932e1d7bba5cd85c2ac205ec75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 17 Mar 2020 16:38:22 -0700 Subject: [PATCH 067/226] doc: west: add pointer to board porting guide for flash/debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The board porting guide now has useful information on supporting flash/debug commands. Link to it from the top of the page describing these commands to hopefully make it easier to find. Signed-off-by: Martí Bolívar --- doc/guides/west/build-flash-debug.rst | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 04a59710..ed3b0c47 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -7,12 +7,8 @@ Zephyr provides several :ref:`west extension commands ` for building, flashing, and interacting with Zephyr programs running on a board: ``build``, ``flash``, ``debug``, ``debugserver`` and ``attach``. -These use information stored in the CMake cache [#cmakecache]_ to -flash or attach a debugger to a board supported by Zephyr. The exception is -starting a clean build (i.e. with no previous artifacts) which will in fact -run CMake thus creating the corresponding cache. -The CMake build system commands with the same names (i.e. all but ``build``) -directly delegate to West. +For information on adding board support for the flashing and debugging +commands, see :ref:`flash-and-debug-support` in the board porting guide. .. Add a per-page contents at the top of the page. This page is nested deeply enough that it doesn't have any subheadings in the main nav. @@ -612,12 +608,6 @@ commands do it). .. rubric:: Footnotes -.. [#cmakecache] - - The CMake cache is a file containing saved variables and values - which is created by CMake when it is first run to generate a build - system. See the `cmake(1)`_ manual for more details. - .. _cmake(1): https://cmake.org/cmake/help/latest/manual/cmake.1.html From a345ec9de5f4efa66d350d88a31c99905f8839d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 31 Mar 2020 11:07:32 -0700 Subject: [PATCH 068/226] doc: west: add FAQ for missing extension command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "why can't I run west build" is a common enough question to add an FAQ item for it in the troubleshooting page. Even if people don't read it, we can still link to it on Slack etc. when the question gets asked. Signed-off-by: Martí Bolívar --- doc/guides/west/troubleshooting.rst | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/doc/guides/west/troubleshooting.rst b/doc/guides/west/troubleshooting.rst index fc2e31d4..bd952a6e 100644 --- a/doc/guides/west/troubleshooting.rst +++ b/doc/guides/west/troubleshooting.rst @@ -5,6 +5,58 @@ Troubleshooting West This page covers common issues with west and how to solve them. +"invalid choice: 'build'" (or 'flash', etc.) +******************************************** + +If you see an unexpected error like this when trying to run a Zephyr extension +command (like :ref:`west flash `, :ref:`west build +`, etc.): + +.. code-block:: none + + $ west build [...] + west: error: argument : invalid choice: 'build' (choose from 'init', [...]) + + $ west flash [...] + west: error: argument : invalid choice: 'flash' (choose from 'init', [...]) + +The most likely cause is that you're running the command outside of a +:ref:`west workspace `. West needs to know where your workspace +is to find :ref:`west-extensions`. + +To fix this, you have two choices: + +#. Run the command from inside a workspace (e.g. the :file:`zephyrproject` + directory you created when you :ref:`got started `). + + For example, create your build directory inside the workspace, or run ``west + flash --build-dir YOUR_BUILD_DIR`` from inside the workspace. + +#. Set the :envvar:`ZEPHYR_BASE` :ref:`environment variable ` and re-run + the west extension command. If set, west will use :envvar:`ZEPHYR_BASE` to + find your workspace. + +If you're unsure whether a command is built-in or an extension, run ``west +help`` from inside your workspace. The output prints extension commands +separately, and looks like this for mainline Zephyr: + +.. code-block:: none + + $ west help + + built-in commands for managing git repositories: + init: create a west workspace + [...] + + other built-in commands: + help: get help for west or a command + [...] + + extension commands from project manifest (path: zephyr): + build: compile a Zephyr application + flash: flash and run a binary on a board + [...] + "invalid choice: 'post-init'" ***************************** From 3a4ccec66aef086fc36eb5f0fdb06ace35912b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 31 Mar 2020 11:21:27 -0700 Subject: [PATCH 069/226] doc: west: add FAQ for requires_workspace issue #373 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is also a common problem. Signed-off-by: Martí Bolívar --- doc/guides/west/troubleshooting.rst | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/doc/guides/west/troubleshooting.rst b/doc/guides/west/troubleshooting.rst index bd952a6e..d4c075b8 100644 --- a/doc/guides/west/troubleshooting.rst +++ b/doc/guides/west/troubleshooting.rst @@ -5,6 +5,47 @@ Troubleshooting West This page covers common issues with west and how to solve them. +"Error: unexpected keyword argument 'requires_workspace'" +********************************************************* + +This error occurs on some Linux distributions after upgrading to west 0.7.0 or +later from 0.6.x. For example: + +.. code-block:: none + + $ west update + [... stack trace ...] + TypeError: __init__() got an unexpected keyword argument 'requires_workspace' + +This appears to be a problem with the distribution's pip; see `this comment in +west issue 373`_ for details. Some versions of **Ubuntu** and **Linux Mint** are known to +have this problem. Some users report issues on Fedora as well. + +Neither macOS nor Windows users have reported this issue. There have been no +reports of this issue on other Linux distributions, like Arch Linux, either. + +.. _this comment in west issue 373: + https://github.com/zephyrproject-rtos/west/issues/373#issuecomment-583489272 + +**Workaround 1**: remove the old version, then upgrade: + +.. code-block:: none + + $ pip3 show west | grep Location: | cut -f 2 -d ' ' + /home/foo/.local/lib/python3.6/site-packages + $ rm -r /home/foo/.local/lib/python3.6/site-packages/west + $ pip3 install --user west==0.7.0 + +**Workaround 2**: install west in a Python virtual environment + +One option is to use the `venv module`_ that's part of the Python 3 standard +library. Some distributions remove this module from their base Python 3 +packages, so you may need to do some additional work to get it installed on +your system. + +.. _venv module: + https://docs.python.org/3/library/venv.html + "invalid choice: 'build'" (or 'flash', etc.) ******************************************** From 7475694c96d69f7fb8ad029556552420b6a58b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 7 Apr 2020 12:06:57 -0700 Subject: [PATCH 070/226] doc: west: link to modules page instead of source code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When this west doc page was written, we didn't have any documentation for modules. We do now, so point to it instead of CMake. Signed-off-by: Martí Bolívar --- doc/guides/west/repo-tool.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 69ca1592..cc596cea 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -68,8 +68,7 @@ manifest directory, and they can be inside of arbitrary subdirectories inside the workspace's root directory. By default, the Zephyr build system uses west to get the locations of all the projects in the workspace, so any code they contain can be used by applications. This behavior can be overridden using -the ``ZEPHYR_MODULES`` CMake variable; see -:zephyr_file:`cmake/zephyr_module.cmake` for details. +the ``ZEPHYR_MODULES`` CMake variable; see :ref:`modules` for details. Finally, any repository managed by a west workspace can contain :ref:`extension commands `, which are extra west commands From 5ec755e92faf2f7d14894c573b3d42f44fbd56ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 18 Aug 2020 12:17:56 -0700 Subject: [PATCH 071/226] doc: west: troubleshoot no west on PATH on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Depending on how people set up their Python, west might not be on PATH. I'd like to have a special-purpose step by step guide for how to handle this in the documentation to save support time when this happens. I think it's worth special casing since west is the first runnable program that pip installs onto a new user's system when they're following the GSG. Signed-off-by: Martí Bolívar --- doc/guides/west/troubleshooting.rst | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/doc/guides/west/troubleshooting.rst b/doc/guides/west/troubleshooting.rst index d4c075b8..0d354df3 100644 --- a/doc/guides/west/troubleshooting.rst +++ b/doc/guides/west/troubleshooting.rst @@ -5,6 +5,48 @@ Troubleshooting West This page covers common issues with west and how to solve them. +"'west' is not recognized as an internal or external command, operable program or batch file.' +********************************************************************************************** + +On Windows, this means that either west is not installed, or your :envvar:`PATH` +environment variable does not contain the directory where pip installed +:file:`west.exe`. + +First, make sure you've installed west; see :ref:`west-install`. Then try +running ``west`` from a new ``cmd.exe`` window. If that still doesn't work, +keep reading. + +You need to find the directory containing :file:`west.exe`, then add it to your +:envvar:`PATH`. (This :envvar:`PATH` change should have been done for you when +you installed Python and pip, so ordinarily you should not need to follow these +steps.) + +Run this command in ``cmd.exe``:: + + pip3 show west + +Then: + +#. Look for a line in the output that looks like ``Location: + C:\foo\python\python38\lib\site-packages``. The exact location + will be different on your computer. +#. Look for a file named ``west.exe`` in the ``scripts`` directory + ``C:\foo\python\python38\scripts``. + + .. important:: + + Notice how ``lib\site-packages`` in the ``pip3 show`` output was changed + to ``scripts``! +#. If you see ``west.exe`` in the ``scripts`` directory, add the full path to + ``scripts`` to your :envvar:`PATH` using a command like this:: + + setx PATH "%PATH%;C:\foo\python\python38\scripts" + + **Do not just copy/paste this command**. The ``scripts`` directory location + will be different on your system. +#. Close your ``cmd.exe`` window and open a new one. You should be able to run + ``west``. + "Error: unexpected keyword argument 'requires_workspace'" ********************************************************* From 96a6f577aed34db7697b228901db6f57ca517f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 31 Aug 2020 14:55:54 -0700 Subject: [PATCH 072/226] doc: west: update west sign documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the documentation to reflect the easier flow. Signed-off-by: Martí Bolívar --- doc/guides/west/build-flash-debug.rst | 37 +++----- doc/guides/west/sign.rst | 130 +++++++++++++++----------- 2 files changed, 89 insertions(+), 78 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index ed3b0c47..8a67a24e 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -531,35 +531,20 @@ For example, to print usage information about the ``jlink`` runner:: .. _west-runner: -runners package API -******************* +Flash and debug runners +*********************** -The flash and debug commands are implemented as west *extension -commands*: that is, they are west commands whose source code lives -outside the west repository. Some reasons this choice was made are: +The flash and debug commands use Python wrappers around various +:ref:`debug-host-tools`. These wrappers are all defined in a Python library at +:zephyr_file:`scripts/west_commands/runners`. Each wrapper is called a +*runner*. Runners can flash and/or debug Zephyr programs. -- Their implementations are tightly coupled to the Zephyr build - system, e.g. due to their reliance on CMake cache variables. - -- Pull requests adding features to them are almost always motivated by - a corresponding change to an upstream board, so it makes sense to - put them in Zephyr to avoid needing pull requests in multiple - repositories. - -- Many users find it natural to search for their implementations in - the Zephyr source tree. - -The extension commands are a thin wrapper around a package called -``runners`` (this package is also in the Zephyr tree, in -:zephyr_file:`scripts/west_commands/runners`). - -The central abstraction within this library is ``ZephyrBinaryRunner``, -an abstract class which represents *runner* objects, which can flash -and/or debug Zephyr programs. The set of available runners is +The central abstraction within this library is ``ZephyrBinaryRunner``, an +abstract class which represents runners. The set of available runners is determined by the imported subclasses of ``ZephyrBinaryRunner``. -``ZephyrBinaryRunner`` is available in the ``runners.core`` module; -individual runner implementations are in other submodules, such as -``runners.nrfjprog``, ``runners.openocd``, etc. +``ZephyrBinaryRunner`` is available in the ``runners.core`` module; individual +runner implementations are in other submodules, such as ``runners.nrfjprog``, +``runners.openocd``, etc. Hacking ******* diff --git a/doc/guides/west/sign.rst b/doc/guides/west/sign.rst index 5fe5828e..a386d0f4 100644 --- a/doc/guides/west/sign.rst +++ b/doc/guides/west/sign.rst @@ -3,65 +3,91 @@ Signing Binaries ################ -This page documents the ``west sign`` :ref:`extension ` -command included in the zephyr repository. It is used to sign a Zephyr -application binary for consumption by a bootloader using an external tool. - -Currently, it supports signing binaries for use with the `MCUboot`_ bootloader, -using the `imgtool`_ program provided by its developers. Using ``west sign`` as -a wrapper around ``imgtool`` for Zephyr binaries is more convenient than using -``imgtool`` directly, because ``west sign`` knows how to read numeric values -needed by ``imgtool`` out of an application build directory. These values -differ depending on your :ref:`board `, so using ``west sign`` means -both shorter command lines and not having to learn or memorize -hardware-specific details. - -To produce signed ``.bin`` and ``.hex`` files for a Zephyr application, make -sure ``imgtool`` is installed (e.g. with ``pip3 install imgtool`` on macOS and -Windows, and ``pip3 install --user imgtool`` on Linux), then run: +The ``west sign`` :ref:`extension ` command can be used to +sign a Zephyr application binary for consumption by a bootloader using an +external tool. Run ``west sign -h`` for command line help. -.. code-block:: console - - west sign -t imgtool -d YOUR_BUILD_DIR -- --key YOUR_SIGNING_KEY.pem - -Above, :file:`YOUR_BUILD_DIR` is a Zephyr build directory containing an -application compiled for MCUboot (in practice, this means -:option:`CONFIG_BOOTLOADER_MCUBOOT` is ``y`` in the application's Kconfig). - -Some additional notes follow. See ``west sign -h`` for detailed help. +MCUboot / imgtool +***************** -- The default ``-d`` value is ``build``, which is the default output directory - created by :ref:`west build `. -- If you don't have your own signing key and have a default MCUboot build, use - ``--key path/to/mcuboot/root-rsa-2048.pem``. -- By default, the output files produced by ``west sign`` are named - :file:`zephyr.signed.bin` and :file:`zephyr.signed.hex` and are created in the - build directory next to the unsigned :file:`zephyr.bin` and :file:`zephyr.hex` - versions. +The Zephyr build system has special support for signing binaries for use with +the `MCUboot`_ bootloader using the `imgtool`_ program provided by its +developers. You can both build and sign this type of application binary in one +step by setting some Kconfig options. If you do, ``west flash`` will use the +signed binaries. - You can control this using the ``-B`` and ``-H`` options, e.g. this would - create :file:`my-signed.bin` and :file:`my-signed.hex` in the current working - directory instead: +If you use this feature, you don't need to run ``west sign`` yourself; the +build system will do it for you. - .. code-block:: console - - west sign -t imgtool -B my-signed.bin -H my-signed.hex [...] - -Example build flow -****************** - -For reference, here is an example showing how to build :ref:`hello_world` for -MCUboot using ``west``: +Here is an example workflow, which builds and flashes MCUboot, as well as the +:ref:`hello_world` application for chain-loading by MCUboot. Run these commands +from the :file:`zephyrproject` workspace you created in the +:ref:`getting_started`. .. code-block:: console - west build -b YOUR_BOARD samples/hello_world -- -DCONFIG_BOOTLOADER_MCUBOOT=y - west sign -t imgtool -- --key YOUR_SIGNING_KEY.pem - west flash --hex-file build/zephyr/zephyr.signed.hex - -The availability of a hex file, and whether ``west flash`` uses it to flash, -depends on your board and build configuration. At least the west flash runners -using ``nrfjprog`` and ``pyocd`` work with the above flow. + west build -b YOUR_BOARD -s bootloader/mcuboot/boot/zephyr -d build-mcuboot + west build -b YOUR_BOARD -s zephyr/samples/hello_world -d build-hello-signed -- \ + -DCONFIG_BOOTLOADER_MCUBOOT=y \ + -DCONFIG_MCUBOOT_SIGNATURE_KEY_FILE=\"bootloader/mcuboot/root-rsa-2048.pem\" + + west flash -d build-mcuboot + west flash -d build-hello-signed + +Notes on the above commands: + +- ``YOUR_BOARD`` should be changed to match your board +- The ``CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`` value is the insecure default + provided and used by by MCUboot for development and testing +- You can change the ``hello_world`` application directory to any other + application that can be loaded by MCUboot, such as the :ref:`smp_svr_sample` + +For more information on these and other related configuration options, see: + +- :option:`CONFIG_BOOTLOADER_MCUBOOT`: build the application for loading by + MCUboot +- :option:`CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`: the key file to use with ``west + sign``. If you have your own key, change this appropriately +- :option:`CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS`: optional additional command line + arguments for ``imgtool`` +- :option:`CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE`: also generate a confirmed + image, which may be more useful for flashing in production environments than + the OTA-able default image +- On Windows, if you get "Access denied" issues, the recommended fix is + to run ``pip3 install imgtool``, then retry with a pristine build directory. + +If your ``west flash`` :ref:`runner ` uses an image format +supported by imgtool, you should see something like this on your device's +serial console when you run ``west flash -d build-mcuboot``: + +.. code-block:: none + + *** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 *** + [00:00:00.004,669] mcuboot: Starting bootloader + [00:00:00.011,169] mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3 + [00:00:00.021,636] mcuboot: Boot source: none + [00:00:00.027,313] mcuboot: Failed reading image headers; Image=0 + [00:00:00.035,064] mcuboot: Unable to find bootable image + +Then, you should see something like this when you run ``west flash -d +build-hello-signed``: + +.. code-block:: none + + *** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 *** + [00:00:00.004,669] mcuboot: Starting bootloader + [00:00:00.011,169] mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3 + [00:00:00.021,636] mcuboot: Boot source: none + [00:00:00.027,374] mcuboot: Swap type: none + [00:00:00.115,142] mcuboot: Bootloader chainload address offset: 0xc000 + [00:00:00.123,168] mcuboot: Jumping to the first image slot + *** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 *** + Hello World! nrf52840dk_nrf52840 + +Whether ``west flash`` supports this feature depends on your runner. The +``nrfjprog`` and ``pyocd`` runners work with the above flow. If your runner +does not support this flow and you would like it to, please send a patch or +file an issue for adding support. .. _MCUboot: https://mcuboot.com/ From c0f497b559db1c17f20034f9208a4d2250eab9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 17 Sep 2020 10:52:42 -0700 Subject: [PATCH 073/226] doc: west: add information about private repositories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit How to manage repositories that require authentication to fetch from using west is a frequently asked question. TL;DR on the answer is that Git already has credential storage built in, so our expectation is that there is nothing west needs to do in particular, as users can select whatever credential helper works for them, or set up a custom one using something like the GIT_ASKPASS environment variable. That's not a very helpful expectation if people aren't aware that credential helpers exist, though, so let's document that and provide examples for common use cases, as well as west-specific troubleshooting advice. Signed-off-by: Martí Bolívar --- doc/guides/west/repo-tool.rst | 108 ++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index cc596cea..daa23719 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -389,6 +389,114 @@ discussed here. Run ``west -h`` for detailed help. - ``west topdir``: Prints the top directory of the west workspace. +Private repositories +******************** + +You can use west to fetch from private repositories. There is nothing +west-specific about this. + +The ``west update`` command essentially runs ``git fetch YOUR_PROJECT_URL`` +when a project's ``manifest-rev`` branch must be updated to a newly fetched +commit. It's up to your environment to make sure the fetch succeeds. + +You can either enter the password manually or use any of the `credential +helpers built in to Git`_. Since Git has credential storage built in, there is +no need for a west-specific feature. + +The following sections cover common cases for running ``west update`` without +having to enter your password, as well as how to troubleshoot issues. + +.. _credential helpers built in to Git: + https://git-scm.com/docs/gitcredentials + +Fetching via HTTPS +================== + +On Windows when fetching from GitHub, recent versions of Git prompt you for +your GitHub password in a graphical window once, then store it for future use +(in a default installation). Passwordless fetching from GitHub should therefore +work "out of the box" on Windows after you have done it once. + +In general, you can store your credentials on disk using the "store" git +credential helper. See the `git-credential-store`_ manual page for details. + +To use this helper for all the repositories in your workspace, run: + +.. code-block:: shell + + west forall -c "git config credential.helper store" + +To use this helper on just the projects ``foo`` and ``bar``, run: + +.. code-block:: shell + + west forall -c "git config credential.helper store" foo bar + +To use this helper by default on your computer, run: + +.. code-block:: shell + + git config --global credential.helper store + +On GitHub, you can set up a `personal access token`_ to use in place of your +account password. (This may be required if your account has two-factor +authentication enabled, and may be preferable to storing your account password +in plain text even if two-factor authentication is disabed.) + +If you don't want to store any credentials on the file system, you can store +them in memory temporarily using `git-credential-cache`_ instead. + +.. _git-credential-store: + https://git-scm.com/docs/git-credential-store#_examples +.. _git-credential-cache: + https://git-scm.com/docs/git-credential-cache +.. _personal access token: + https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token + +Fetching via SSH +================ + +If your SSH key has no password, fetching should just work. If it does have a +password, you can avoid entering it manually every time using `ssh-agent`_. + +On GitHub, see `Connecting to GitHub with SSH`_ for details on configuration +and key creation. + +.. _ssh-agent: + https://www.ssh.com/ssh/agent +.. _Connecting to GitHub with SSH: + https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh + +Troubleshooting +=============== + +One good way to troubleshoot fetching issues is to run ``west update`` in +verbose mode, like this: + +.. code-block:: shell + + west -v update + +The output includes Git commands run by west and their outputs. Look for +something like this: + +.. code-block:: none + + === updating your_project (path/to/your/project): + west.manifest: your_project: checking if cloned + [...other west.manifest logs...] + --- your_project: fetching, need revision SOME_SHA + west.manifest: running 'git fetch ... https://github.com/your-username/your_project ...' in /some/directory + +The ``git fetch`` command example in the last line above is what needs to +succeed. Go to ``/some/directory``, copy/paste and run the entire ``git fetch`` +command, then debug from there using the documentation for your credential +storage helper. + +If you can get the ``git fetch`` command to run successfully without prompting +for a password when you run it directly, you will be able to run ``west +update`` without entering your password in that same shell. + .. _PyPI: https://pypi.org/project/west/ From 122dd3f85bb156ff3c1cfa4cfda7256f8072dad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 9 Sep 2020 12:29:46 -0700 Subject: [PATCH 074/226] doc: west: add missing 0.7.x docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I neglected to update the release notes when cutting these. Whoops. Signed-off-by: Martí Bolívar --- doc/guides/west/release-notes.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index bd705813..50cf3b53 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,6 +1,35 @@ West Release Notes ################## +v0.7.3 +****** + +This is a bugfix release. + +- Fix an error where a failed import could leave the workspace in an unusable + state (see [PR #415](https://github.com/zephyrproject-rtos/west/pull/415) for + details) + +v0.7.2 +****** + +This is a bugfix and minor feature release. + +- Filter out duplicate extension commands brought in by manifest imports +- Fix ``west.Manifest.get_projects()`` when finding the manifest repository by + path + +v0.7.1 +****** + +This is a bugfix and minor feature release. + +- ``west update --stats`` now prints timing for operations which invoke a + subprocess, time spent in west's Python process for each project, and total + time updating each project. +- ``west topdir`` always prints a POSIX style path +- minor console output changes + v0.7.0 ****** From d45fa4282fe965f62667d15ea0faee324ef094cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 9 Sep 2020 13:20:10 -0700 Subject: [PATCH 075/226] doc: west: API doc cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use italics more consistently when referring to parameters by name. Make the ImportFlag members appear. Signed-off-by: Martí Bolívar --- doc/guides/west/west-apis.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 41328d1c..2016c987 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -231,7 +231,7 @@ Manifest and sub-objects .. automethod:: __init__ .. versionchanged:: 0.7.0 - The ``importer`` and ``import_flags`` keyword arguments. + The *importer* and *import_flags* keyword arguments. .. automethod:: from_file .. versionchanged:: 0.7.0 @@ -239,7 +239,7 @@ Manifest and sub-objects .. automethod:: from_data .. versionchanged:: 0.7.0 - ``**kwargs`` added, and ``source_data`` may be a ``str``. + ``**kwargs`` added, and *source_data* may be a ``str``. Conveniences for accessing sub-objects by name or other identifier: @@ -257,17 +257,19 @@ Manifest and sub-objects .. versionadded:: 0.7.0 .. autoclass:: west.manifest.ImportFlag + :members: + :member-order: bysource .. autoclass:: west.manifest.Project .. (note: attributes are part of the class docstring) .. versionchanged:: 0.7.0 - The ``remote`` attribute was removed. Its semantics could no longer + The *remote* attribute was removed. Its semantics could no longer be preserved when support for manifest ``import`` keys was added. .. versionadded:: 0.7.0 - The ``remote_name`` and ``name_and_path`` attributes. + The *remote_name* and *name_and_path* attributes. Constructor: @@ -283,7 +285,7 @@ Manifest and sub-objects .. automethod:: git .. versionchanged:: 0.6.1 - The ``capture_stderr`` kwarg. + The *capture_stderr* kwarg. .. versionchanged:: 0.7.0 The (now removed) ``Project.format`` method is no longer called on arguments. From 8c47e4746e0d7dee1f83b26d97e98f290b874a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 9 Sep 2020 13:28:21 -0700 Subject: [PATCH 076/226] doc: west: changes for v0.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track changes in the APIs and CLIs for this release. Signed-off-by: Martí Bolívar --- doc/guides/west/index.rst | 25 +++++---- doc/guides/west/manifest.rst | 84 +++++++++++++++++++++++++++++++ doc/guides/west/release-notes.rst | 24 +++++++++ doc/guides/west/west-apis.rst | 46 +++++++++++++++++ 4 files changed, 166 insertions(+), 13 deletions(-) diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index cc6c058d..fd0f1b38 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -4,30 +4,29 @@ West (Zephyr's meta-tool) ######################### The Zephyr project includes a swiss-army knife command line tool named -``west``\ [#west-name]_. West is developed in its own `repository`_. Like -``git`` and ``docker``, the top-level ``west`` command takes some common +``west``\ [#west-name]_. West is developed in its own `repository`_. + +West's built-in commands provide a multiple repository management system with +features inspired by Google's Repo tool and Git submodules. West is also +"pluggable": you can write your own west extension commands which add +additional features to west. Zephyr uses this to provide conveniences for +building applications, flashing and debugging them, and more. + +Like ``git`` and ``docker``, the top-level ``west`` command takes some common options, a sub-command to run, and then options and arguments for that sub-command:: west [common-opts] [opts] -West's built-in commands provide a multiple repository management -system with features inspired by Google's Repo tool and Git -submodules. West simplifies configuration and is also pluggable: you -can write your own west "extension commands" which add additional -features to west. Zephyr uses this feature to provide conveniences -for building applications, flashing and debugging them, and more. +Since west v0.8, you can also run west like this:: -It is possible not to use west for Zephyr development if you do not -require these features, prefer to use your own tools, or want to -eliminate the extra layer of indirection. However, this implies extra -effort and expert knowledge. + python3 -m west [common-opts] [opts] You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.7.x`` releases, and provide additional +The following pages document west's ``v0.8.x`` releases, and provide additional context about the tool. .. toctree:: diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 08dcb970..c1b5129c 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -354,6 +354,7 @@ these in order, using examples: - :ref:`west-manifest-ex3.1` - :ref:`west-manifest-ex3.2` - :ref:`west-manifest-ex3.3` + - :ref:`west-manifest-ex3.4` - :ref:`Sequence of paths and mappings ` - :ref:`west-manifest-ex4.1` - :ref:`west-manifest-ex4.2` @@ -757,6 +758,10 @@ The ``import`` key can also contain a mapping with the following keys: names to exclude rather than include. - ``path-blacklist``: Optional. Like ``path-whitelist``, but contains project paths to exclude rather than include. +- ``path-prefix``: Optional (new in v0.8.0). If given, this will be prepended + to the project's path in the workspace, as well as the paths of any imported + projects. This can be used to place these projects in a subdirectory of the + workspace. .. _re: https://docs.python.org/3/library/re.html .. _pathlib: @@ -948,6 +953,71 @@ An equivalent manifest in a single file would be: path: modules/hals/foo url: https://git.example.com/downstream/hal_foo +.. _west-manifest-ex3.4: + +Example 3.4: Import into a subdirectory +--------------------------------------- + +You want to import a manifest and its projects, placing everything into a +subdirectory of your :term:`west workspace`. + +For example, suppose you want to import this manifest from project ``foo``, +adding this project and its projects ``bar`` and ``baz`` to your workspace: + +.. code-block:: yaml + + # foo/west.yml: + manifest: + defaults: + remote: example + remotes: + - name: example + url-base: https://git.example.com + projects: + - name: bar + - name: baz + +Instead of importing these into the top level workspace, you want to place all +three project repositories in an :file:`external-code` subdirectory, like this: + +.. code-block:: none + + workspace/ + └── external-code/ + ├── foo/ + ├── bar/ + └── baz/ + +You can do this using this manifest: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + url: https://git.example.com/foo + import: + path-prefix: external-code + +An equivalent manifest in a single file would be: + +.. code-block:: yaml + + # foo/west.yml: + manifest: + defaults: + remote: example + remotes: + - name: example + url-base: https://git.example.com + projects: + - name: foo + path: external-code/foo + - name: bar + path: external-code/bar + - name: baz + path: external-code/baz + .. _west-manifest-import-seq: Option 4: Sequence @@ -1167,3 +1237,17 @@ or fails with an error: west manifest --validate The error message can help diagnose errors. + +.. _west-manifest-path: + +Get the manifest path +===================== + +The ``--path`` action prints the path to the top level manifest file: + +.. code-block:: none + + west manifest --path + +The output is something like ``/path/to/workspace/west.yml``. The path format +depends on your operating system. diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 50cf3b53..5955fa7a 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,6 +1,30 @@ West Release Notes ################## +v0.8.0 +****** + +This is a feature release which changes the manifest schema by adding support +for a ``path-prefix:`` key in an ``import:`` mapping, along with some other +features and fixes. + +- Manifest import mappings now support a ``path-prefix:`` key, which foo places + the project and its imported repositories in a subdirectory of the workspace. + See :ref:`west-manifest-ex3.4` for an example. +- The west command line application can now also be run using ``python3 -m + west``. This makes it easier to run west under a particular Python + interpreter without modifying the :envvar:`PATH` environment variable. +- :ref:`west manifest --path ` prints the absolute path to + west.yml +- ``west init`` now supports an ``--mf foo.yml`` option, which initializes the + workspace using :file:`foo.yml` instead of :file:`west.yml`. +- ``west list`` now prints the manifest repository's path using the + ``manifest.path`` :ref:`configuration option `, which may differ + from the ``self: path:`` value in the manifest data. The old behavior is + still available, but requires passing a new ``--manifest-path-from-yaml`` + option. +- Various Python API changes; see :ref:`west-apis` for details. + v0.7.3 ****** diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 2016c987..2bd3efc3 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -93,6 +93,8 @@ WestCommand .. automethod:: __init__ + .. versionchanged:: 0.8.0 + The *topdir* parameter can now be any ``os.PathLike``. .. versionadded:: 0.6.0 The *requires_installation* parameter. .. versionadded:: 0.7.0 @@ -141,6 +143,9 @@ Reading and writing options .. autofunction:: west.configuration.read_config +.. versionchanged:: 0.8.0 + The deprecated *read_config* parameter was removed. + .. versionchanged:: 0.6.0 Errors due to an inability to find a local configuration file are ignored. @@ -234,6 +239,9 @@ Manifest and sub-objects The *importer* and *import_flags* keyword arguments. .. automethod:: from_file + .. versionchanged:: 0.8.0 + The *source_file*, *manifest_path*, and *topdir* arguments + can now be any ``os.PathLike``. .. versionchanged:: 0.7.0 ``**kwargs`` added. @@ -244,6 +252,8 @@ Manifest and sub-objects Conveniences for accessing sub-objects by name or other identifier: .. automethod:: get_projects + .. versionchanged:: 0.8.0 + The *project_ids* sequence can now contain any ``os.PathLike``. .. versionadded:: 0.6.1 Additional methods: @@ -264,6 +274,10 @@ Manifest and sub-objects .. (note: attributes are part of the class docstring) + .. versionchanged:: 0.8.0 + The *west_commands* attribute is now always a list. In previous + releases, it could be a string or ``None``. + .. versionchanged:: 0.7.0 The *remote* attribute was removed. Its semantics could no longer be preserved when support for manifest ``import`` keys was added. @@ -275,6 +289,9 @@ Manifest and sub-objects .. automethod:: __init__ + .. versionchanged:: 0.8.0 + The *path* and *topdir* parameters can now be any ``os.PathLike``. + .. versionchanged:: 0.7.0 The parameters were incompatibly changed from previous versions. @@ -295,18 +312,30 @@ Manifest and sub-objects Standard error is now captured. .. automethod:: is_ancestor_of + .. versionchanged:: 0.8.0 + The *cwd* parameter can now be any ``os.PathLike``. .. automethod:: is_cloned + .. versionchanged:: 0.8.0 + The *cwd* parameter can now be any ``os.PathLike``. .. versionadded:: 0.6.1 .. automethod:: is_up_to_date_with + .. versionchanged:: 0.8.0 + The *cwd* parameter can now be any ``os.PathLike``. .. automethod:: is_up_to_date + .. versionchanged:: 0.8.0 + The *cwd* parameter can now be any ``os.PathLike``. .. automethod:: read_at + .. versionchanged:: 0.8.0 + The *cwd* parameter can now be any ``os.PathLike``. .. versionadded:: 0.7.0 .. automethod:: listdir_at + .. versionchanged:: 0.8.0 + The *cwd* parameter can now be any ``os.PathLike``. .. versionadded:: 0.7.0 .. autoclass:: west.manifest.ManifestProject @@ -314,6 +343,11 @@ Manifest and sub-objects A limited subset of Project methods is supported. Results for calling others are not specified. + .. versionchanged:: 0.8.0 + The *url* attribute is now the empty string instead of ``None``. + The *abspath* attribute is created using ``os.path.abspath()`` + instead of ``os.path.realpath()``, improving support for symbolic links. + .. automethod:: as_dict .. versionadded:: 0.6.0 @@ -330,9 +364,15 @@ Exceptions .. autoclass:: west.manifest.ManifestVersionError :show-inheritance: + .. versionchanged:: 0.8.0 + The *file* argument can now be any ``os.PathLike``. + .. autoclass:: west.manifest.ManifestImportFailed :show-inheritance: + .. versionchanged:: 0.8.0 + The *filename* argument can now be any ``os.PathLike``. + .. _west-apis-util: west.util @@ -347,8 +387,14 @@ Functions .. autofunction:: west.util.west_dir + .. versionchanged:: 0.8.0 + The *start* parameter can be any ``os.PathLike``. + .. autofunction:: west.util.west_topdir + .. versionchanged:: 0.8.0 + The *start* parameter can be any ``os.PathLike``. + Exceptions ========== From 54447c75df8ce20382e96367e209cde355f324f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 6 Oct 2020 06:44:19 -0700 Subject: [PATCH 077/226] doc: west: fix typo in release notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a copy/paste error here. Signed-off-by: Martí Bolívar --- doc/guides/west/release-notes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 5955fa7a..b2eb7355 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -8,7 +8,7 @@ This is a feature release which changes the manifest schema by adding support for a ``path-prefix:`` key in an ``import:`` mapping, along with some other features and fixes. -- Manifest import mappings now support a ``path-prefix:`` key, which foo places +- Manifest import mappings now support a ``path-prefix:`` key, which places the project and its imported repositories in a subdirectory of the workspace. See :ref:`west-manifest-ex3.4` for an example. - The west command line application can now also be run using ``python3 -m From 707891f4cd41e0aaf23f9581b065ac90cd8c0236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 7 Oct 2020 06:33:11 -0700 Subject: [PATCH 078/226] doc: update west build --pristine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This needs to be changed to reflect the change of default to 'auto' from 'never'. Signed-off-by: Martí Bolívar --- doc/guides/west/build-flash-debug.rst | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 8a67a24e..c1065f3a 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -141,22 +141,24 @@ Pristine Builds A *pristine* build directory is essentially a new build directory. All byproducts from previous builds have been removed. -To have ``west build`` make the build directory pristine before re-running -CMake to generate a build system, use the ``--pristine`` (or ``-p``) -option. For example, to switch board and application (which requires a pristine -build directory) in one command:: +To force ``west build`` make the build directory pristine before re-running +CMake to generate a build system, use the ``--pristine=always`` (or +``-p=always``) option. - west build -b qemu_x86 samples/philosophers - west build -p -b reel_board samples/hello_world +Giving ``--pristine`` or ``-p`` without a value has the same effect as giving +it the value ``always``. For example, these commands are equivalent:: -To let west decide for you if a pristine build is needed, use ``-p auto``:: + west build -p -b reel_board samples/hello_world + west build -p=always -b reel_board samples/hello_world - west build -p auto -b reel_board samples/hello_world +By default, ``west build`` applies a heuristic to detect if the build directory +needs to be made pristine. This is the same as using ``--pristine=auto``. .. tip:: - You can run ``west config build.pristine auto`` to make this setting - permanent. + You can run ``west config build.pristine always`` to always do a pristine + build, or ``west config build.pristine never`` to disable the heuristic. + See the ``west build`` :ref:`west-building-config` for details. .. _west-building-verbose: From 7b71fc4f6022ec382a8f0f4c06e974a21546da92 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 7 Oct 2020 23:57:04 -0700 Subject: [PATCH 079/226] doc: west: add inline comments in the tree and manifest examples It's great to have full manifest examples that can actually work as they are, however the number of lines can "dilute" the feature currently described and distract from it. Add some comments in the manifests to highlight the current topic(s). The file tree examples and their descriptions are carefully made up and generally excellent, however I found my eyes going constantly back and forth between the two in order to match them with one another and build the actual, graphical representation in my head. These new comments attached to the major elements of the trees will IMHO accelerate that visual representation. What I found especially lacking: clues about which directories are .git/ clones; a pity in the pages specifically about git clone organization. Signed-off-by: Marc Herbert --- doc/guides/west/manifest.rst | 49 +++++++++++------------ doc/guides/west/repo-tool.rst | 73 ++++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 55 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index c1b5129c..35968c23 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -416,15 +416,16 @@ In other words, the west workspace you want looks like this: .. code-block:: none - my-downstream - ├── .west # west directory - ├── zephyr # mainline zephyr repository - ├── modules # modules from mainline zephyr - │   ├── hal + my-downstream/ + ├── .west/ # west directory + ├── zephyr/ # mainline zephyr repository + │ └── west.yml # the v1.14.1 version of this file is imported + ├── modules/ # modules from mainline zephyr + │   ├── hal/ │   └── [...other directories..] ├── [ ... other projects ...] # other mainline repositories - └── my-repo # your downstream repository - ├── west.yml + └── my-repo/ # your downstream repository + ├── west.yml # main manifest importing zephyr/west.yml v1.14.1 └── [...other files..] You can do this with the following :file:`my-repo/west.yml`: @@ -529,14 +530,14 @@ This manifest is similar to the one in :ref:`west-manifest-ex1.1`, except it: - name: my-remote url-base: https://git.example.com projects: - - name: hal_nordic + - name: hal_nordic # higher precedence remote: my-remote revision: my-sha path: modules/hal/nordic - name: zephyr remote: zephyrproject-rtos revision: v2.0.0 - import: true + import: true # imported projects have lower precedence # subset of zephyr/west.yml contents at v2.0.0: manifest: @@ -547,7 +548,7 @@ This manifest is similar to the one in :ref:`west-manifest-ex1.1`, except it: url-base: https://github.com/zephyrproject-rtos projects: # ... - - name: hal_nordic + - name: hal_nordic # lower precedence, values ignored path: modules/hal/nordic revision: another-sha @@ -785,13 +786,13 @@ hosted at ``https://git.example.com/mainline/manifest``. # mainline west.yml: manifest: projects: - - name: mainline-app + - name: mainline-app # included path: examples/app url: https://git.example.com/mainline/app - name: lib path: libraries/lib url: https://git.example.com/mainline/lib - - name: lib2 + - name: lib2 # included path: libraries/lib2 url: https://git.example.com/mainline/lib2 @@ -823,10 +824,10 @@ An equivalent manifest in a single file would be: - name: lib3 path: libraries/lib3 url: https://git.example.com/downstream/lib3 - - name: mainline-app + - name: mainline-app # imported path: examples/app url: https://git.example.com/mainline/app - - name: lib2 + - name: lib2 # imported path: libraries/lib2 url: https://git.example.com/mainline/lib2 @@ -850,10 +851,10 @@ using ``path-whitelist``. path: examples/app url: https://git.example.com/mainline/app - name: lib - path: libraries/lib + path: libraries/lib # included url: https://git.example.com/mainline/lib - name: lib2 - path: libraries/lib2 + path: libraries/lib2 # included url: https://git.example.com/mainline/lib2 # downstream west.yml: @@ -875,10 +876,10 @@ An equivalent manifest in a single file would be: manifest: projects: - - name: lib + - name: lib # imported path: libraries/lib url: https://git.example.com/mainline/lib - - name: lib2 + - name: lib2 # imported path: libraries/lib2 url: https://git.example.com/mainline/lib2 - name: mainline @@ -914,11 +915,11 @@ you're targeting, and keep everything else. - name: lib2 path: libraries/lib2 - name: hal_foo - path: modules/hals/foo + path: modules/hals/foo # excluded - name: hal_bar - path: modules/hals/bar + path: modules/hals/bar # excluded - name: hal_baz - path: modules/hals/baz + path: modules/hals/baz # excluded # downstream west.yml: manifest: @@ -942,10 +943,10 @@ An equivalent manifest in a single file would be: - name: mainline url-base: https://git.example.com/mainline projects: - - name: app - - name: lib + - name: app # imported + - name: lib # imported path: libraries/lib - - name: lib2 + - name: lib2 # imported path: libraries/lib2 - name: mainline repo-path: https://git.example.com/mainline/manifest diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index daa23719..0f5fd26c 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -32,16 +32,16 @@ like this: .. code-block:: none - zephyrproject - ├── .west + zephyrproject/ # west topdir + ├── .west/ │ └── config - ├── zephyr - │ ├── west.yml - │ └── [... other files ...] - ├── modules - │ └── lib - │ └── tinycbor - ├── net-tools + ├── zephyr/ # .git/ │ + │ ├── west.yml # manifest │ never modified by west + │ └── [... other files ...] │ + ├── modules/ + │ └── lib/ + │ └── tinycbor/ # .git/ project + ├── net-tools/ # .git/ project └── [ ... other projects ...] Above, :file:`zephyrproject` is the name of the west workspace's root @@ -111,17 +111,23 @@ A workspace using this topology looks like this: .. code-block:: none - west-workspace - ├── application - │   ├── CMakeLists.txt - │   ├── prj.conf - │   ├── src - │   │   └── main.c - │   └── west.yml - ├── modules - │   └── lib - │   └── tinycbor - └── zephyr + west-workspace/ + │ + ├── application/ # .git/ │ + │   ├── CMakeLists.txt │ + │   ├── prj.conf │ never modified by west + │   ├── src/ │ + │   │   └── main.c │ + │   └── west.yml # main manifest with optional import(s) and override(s) + │ │ + ├── modules/ + │   └── lib/ + │   └── tinycbor/ # .git/ project from either the main manifest or some import. + │ + └── zephyr/ # .git/ project + └── west.yml # This can be partially imported with lower precedence or ignored. + # Only the 'manifest-rev' version can be imported. + Here is an example :file:`application/west.yml` which uses :ref:`west-manifest-import`, available since west 0.7, to import Zephyr v2.2.0 @@ -192,23 +198,28 @@ A workspace using this topology looks like this: .. code-block:: none - west-workspace - ├── app1 + west-workspace/ + ├── app1/ # .git/ project │   ├── CMakeLists.txt │   ├── prj.conf - │   └── src + │   └── src/ │   └── main.c - ├── app2 + ├── app2/ # .git/ project │   ├── CMakeLists.txt │   ├── prj.conf - │   └── src + │   └── src/ │   └── main.c - ├── manifest-repo - │   └── west.yml - ├── modules - │   └── lib - │   └── tinycbor - └── zephyr + ├── manifest-repo/ # .git/ never modified by west + │   └── west.yml # main manifest with optional import(s) and override(s) + ├── modules/ + │   └── lib/ + │   └── tinycbor/ # .git/ project from either the main manifest or + │ # frome some import + │ + └── zephyr/ # .git/ project + └── west.yml # This can be partially imported with lower precedence or ignored. + # Only the 'manifest-rev' version can be imported. + Here is an example T3 :file:`manifest-repo/west.yml` which uses :ref:`west-manifest-import`, available since west 0.7, to import Zephyr From 2d8ae10b9b459fa003ebf23ddb9eac2cbf5db3b6 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Fri, 6 Nov 2020 18:46:49 -0300 Subject: [PATCH 080/226] doc: guides: debugging: Move to flash_debug dir The debugging section was generalized for flash and debugging tools. The links were refactored accordly and all references were updated. To be consistent, the directory doc/guides/debbugging was renamed to doc/guides/flash_debug. Signed-off-by: Gerson Fernando Budke --- doc/guides/west/build-flash-debug.rst | 6 +++--- doc/guides/west/without-west.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index c1065f3a..59ad249c 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -537,9 +537,9 @@ Flash and debug runners *********************** The flash and debug commands use Python wrappers around various -:ref:`debug-host-tools`. These wrappers are all defined in a Python library at -:zephyr_file:`scripts/west_commands/runners`. Each wrapper is called a -*runner*. Runners can flash and/or debug Zephyr programs. +:ref:`flash-debug-host-tools`. These wrappers are all defined in a Python +library at :zephyr_file:`scripts/west_commands/runners`. Each wrapper is +called a *runner*. Runners can flash and/or debug Zephyr programs. The central abstraction within this library is ``ZephyrBinaryRunner``, an abstract class which represents runners. The set of available runners is diff --git a/doc/guides/west/without-west.rst b/doc/guides/west/without-west.rst index 7078578f..0f371c04 100644 --- a/doc/guides/west/without-west.rst +++ b/doc/guides/west/without-west.rst @@ -66,7 +66,7 @@ etc. is just a call to the corresponding :ref:`west command `. For example, ``ninja flash`` calls ``west flash``\ [#wbninja]_. If you don't have west installed on your system, running those targets will fail. You can of course still flash and debug using -any :ref:`debug-host-tools` which work for your board (and which those +any :ref:`flash-debug-host-tools` which work for your board (and which those west commands wrap). If you want to use these build system targets but do not want to From e38b7d81d915006a2d8923950adb0ca4f2460910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 6 Jan 2021 00:30:12 -0800 Subject: [PATCH 081/226] doc: improve west's repo-tool.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various improvements to the west repo-tool.rst page and pages that link to it: Rename the page title to "Basics", since it documents, well the basics, including built-in commands like "help" an "config" that are not directly related to multiple repositories. The "multi-repo" term was invented before we started using "workspace". Drop it from the text and rework things using words like "workspace", "basics", or "built-ins" instead, which read better. We've been using west for a long enough time that justifying its existence prominently at the start of this page is no longer necessary; move that to the "dustbin of history" page (why.rst). Try harder to clarify exactly what a "project" is, along with other workspace related clarifications. Improve the documentation for the west init and west update commands, and create :ref: targets for linking directly to them for convenience elsewhere in the docs. Slim down the usages for other built-in commands, so we don't have to keep those up to date as carefully each release. This is about to be important for west 0.9, which is going to change the detailed semantics for the "[PROJECT ...]" part of each command synopsis in a way that will be inconvenient to duplicate for each of these. Move the "Topologies supported" content lower down. Try to help the reading flow by letting people get familiar with a workspace and what you can do with it using the Zephyr GSG workspace that they probably already have before overwhelming them with other possibilities and choices. Signed-off-by: Martí Bolívar --- doc/guides/west/config.rst | 2 +- doc/guides/west/release-notes.rst | 2 +- doc/guides/west/repo-tool.rst | 468 +++++++++++++++++------------- doc/guides/west/why.rst | 4 + 4 files changed, 270 insertions(+), 206 deletions(-) diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index 5a9ee86d..3079d7dc 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -142,7 +142,7 @@ commands are documented in the pages for those commands. * - ``update.fetch`` - String, one of ``"smart"`` (the default behavior starting in v0.6.1) or ``"always"`` (the previous behavior). If set to ``"smart"``, the - :ref:`west update ` command will skip fetching + :ref:`west-update` command will skip fetching from project remotes when those projects' revisions in the manifest file are SHAs or tags which are already available locally. The ``"always"`` behavior is to unconditionally fetch from the remote. diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index b2eb7355..5062b0ad 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -149,7 +149,7 @@ v0.6.1 The user-visible features in this point release are: -- The `west update ` command has a new ``--fetch`` +- The :ref:`west-update` command has a new ``--fetch`` command line flag and ``update.fetch`` :ref:`configuration option `. The default value, "smart", skips fetching SHAs and tags which are available locally. diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 0f5fd26c..de6fa452 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -1,79 +1,289 @@ .. _west-multi-repo: -Multiple Repository Management -############################## +Basics +###### -This page introduces basic concepts related to west and its multiple repository -management features, and gives an overview of the associated commands. See -:ref:`west-history` and `Zephyr issue #6770`_ for additional discussion, -rationale, and motivation. - -.. note:: - - West's multi-repo commands are meant to augment Git in minor ways for - multi-repo work, not to replace it. For tasks that only operate on one - repository, just use plain Git commands. +This page introduces west's basic concepts and built-in commands along with +references to further reading. .. _west-workspace: Introduction ************ -West's built-in commands allow you to work with projects composed of multiple -Git repositories installed under a common parent directory, which we call a -*west workspace* (before west 0.7, this was called a *west installation*). This -works similarly to `Git Submodules -`_ and Google's `repo -`_. +West's built-in commands allow you to work with *projects* (Git +repositories) under a common *workspace* directory. You can create a +workspace using the :ref:`west-init` command. -A west workspace is the result of running the ``west init`` command, which -is described in more detail below. For upstream Zephyr, the workspace looks -like this: +If you've followed the upstream Zephyr getting started guide, your +workspace looks like this: .. code-block:: none zephyrproject/ # west topdir - ├── .west/ - │ └── config - ├── zephyr/ # .git/ │ - │ ├── west.yml # manifest │ never modified by west - │ └── [... other files ...] │ + ├── .west/ # marks the location of the topdir + │ └── config # per-workspace local configuration file + ├── zephyr/ # .git/ repo │ the manifest repository, + │ ├── west.yml # manifest file │ never modified by west + │ └── [... other files ...] │ after creation ├── modules/ │ └── lib/ │ └── tinycbor/ # .git/ project ├── net-tools/ # .git/ project └── [ ... other projects ...] -Above, :file:`zephyrproject` is the name of the west workspace's root -directory. This name is just an example -- it could be anything, like ``z``, -``my-zephyr-workspace``, etc. The file :file:`.west/config` is the -workspace's :ref:`local configuration file `. +Above, :file:`zephyrproject` is the name of the workspace's top level +directory, or *topdir*. (The name :file:`zephyrproject` is just an example +-- it could be anything, like ``z``, ``my-zephyr-workspace``, etc.) + +The topdir contains the :file:`.west` directory. When west needs to find +the topdir, it searches for :file:`.west`, and uses its parent directory. +The search starts from the current working directory (and starts again from +the location in the :envvar:`ZEPHYR_BASE` environment variable as a +fallback if that fails). The file :file:`.west/config` is the workspace's +:ref:`local configuration file `. Every west workspace contains exactly one *manifest repository*, which is a -Git repository containing a file named :file:`west.yml`, which is the *west -manifest*. The location of the manifest repository is given by the -:ref:`manifest.path configuration option ` in the local -configuration file. The manifest file, along with west's configuration files, -controls the workspace's behavior. For upstream Zephyr, :file:`zephyr` is -the manifest repository, but you can configure west to use any Git repository -in the workspace as the manifest repository. The only requirement is that it -contains a valid manifest file. See :ref:`west-manifests` for more details on -what this means. - -Both of the :file:`tinycbor` and :file:`net-tools` directories are *projects* -managed by west, and configured in the manifest file. A west workspace can -contain arbitrarily many projects. As shown above, projects can be located -anywhere in the workspace. They don't have to be subdirectories of the -manifest directory, and they can be inside of arbitrary subdirectories inside -the workspace's root directory. By default, the Zephyr build system uses -west to get the locations of all the projects in the workspace, so any code -they contain can be used by applications. This behavior can be overridden using -the ``ZEPHYR_MODULES`` CMake variable; see :ref:`modules` for details. - -Finally, any repository managed by a west workspace can contain -:ref:`extension commands `, which are extra west commands -provided by that project. This includes the manifest repository and any project -repository. +Git repository containing a *manifest file*. The location of the manifest +repository is given by the :ref:`manifest.path configuration option +` in the local configuration file. + +For upstream Zephyr, :file:`zephyr` is the manifest repository, but you can +configure west to use any Git repository in the workspace as the manifest +repository. The only requirement is that it contains a valid manifest file. +See :ref:`west-topologies` for information on other options, and +:ref:`west-manifests` for details on the manifest file format. + +The manifest file is a YAML file that defines *projects*, which are the +additional Git repositories in the workspace managed by west. The manifest +file is named :file:`west.yml` by default; this can be overridden using the +``manifest.file`` local configuration option. + +You use the :ref:`west-update` command to update the workspace's projects +based on the contents of the manifest file. The manifest file controls +things like where the project should be placed within the workspace, what +URL to clone it from if it's missing, and what Git revision should be +checked out locally. + +Projects can be located anywhere inside the workspace, but they may not +"escape" it. Project repositories need not be located in subdirectories of +the manifest repository or as immediate subdirectories of the topdir. +However, projects must have paths inside the workspace. (You may replace a +project's repository directory within the workspace with a symbolic link to +elsewhere on your computer, but west will not do this for you.) + +A workspace can contain additional Git repositories or other files and +directories not managed by west. West basically ignores anything in the +workspace except :file:`.west`, the manifest repository, and the projects +specified in the manifest file. + +For upstream Zephyr, ``tinycbor`` and ``net-tools`` are projects. They are +specified in the manifest file :file:`zephyr/west.yml`. This file specifies +that ``tinycbor`` is located in the :file:`modules/lib/tinycbor` directory +beneath the workspace topdir. By default, the Zephyr :ref:`build system +` uses west to get the locations of all the projects in the +workspace, so any code they contain can be used as :ref:`modules`. + +Finally, any repository managed by a west workspace (either the manifest +repository or any project repository) can define :ref:`west-extensions`. +Extensions are extra commands not built into west that you can run when +using that workspace. + +The zephyr repository uses this feature to provide Zephyr-specific commands +like :ref:`west build `. Defining these as extensions keeps +west's core agnostic to the specifics of any workspace's Zephyr version, +etc. + +.. _west-struct: + +Structure +********* + +West's code is distributed via PyPI in a Python package named ``west``. +This distribution includes a launcher executable, which is also named +``west`` (or ``west.exe`` on Windows). + +When west is installed, the launcher is placed by :file:`pip3` somewhere in +the user's filesystem (exactly where depends on the operating system, but +should be on the ``PATH`` :ref:`environment variable `). This +launcher is the command-line entry point to running both built-in commmands +like ``west init``, ``west update``, along with any extensions discovered +in the workspace. + +In addition to its command-line interface, you can also use west's Python +APIs directly. See :ref:`west-apis` for details. + +.. _west-manifest-rev: + +The ``manifest-rev`` branch +*************************** + +West creates and controls a Git branch named ``manifest-rev`` in each +project. This branch points to the revision that the manifest file +specified for the project at the time :ref:`west-update` was last run. +Other workspace management commands may use ``manifest-rev`` as a reference +point for the upstream revision as of this latest update. Among other +purposes, the ``manifest-rev`` branch allows the manifest file to use SHAs +as project revisions. + +Although ``manifest-rev`` is a normal Git branch, west will recreate and/or +reset it on the next update. For this reason, it is **dangerous** +to check it out or otherwise modify it yourself. For instance, any commits +you manually add to this branch may be lost the next time you run ``west +update``. Instead, check out a local branch with another name, and either +rebase it on top of a new ``manifest-rev``, or merge ``manifest-rev`` into +it. + +.. note:: + + West does not create a ``manifest-rev`` branch in the manifest repository, + since west does not manage the manifest repository's branches or revisions. + +.. _west-built-in-cmds: + +Built-in Commands +***************** + +This section gives an overview of west's built-in commands. + +Some commands are related to Git commands with the same name, but operate +on the entire workspace. For example, ``west diff`` shows local changes in +multiple Git repositories in the workspace. + +Some commands take projects as arguments. These arguments can be project +names as specified in the manifest file, or (as a fallback) paths to them +on the local file system. Omitting project arguments to commands which +accept them (such as ``west list``, ``west forall``, etc.) usually defaults +to using all projects in the manifest file plus the manifest repository +itself. + +The following documentation does not exhaustively describe all commands. +For additional help, run ``west -h`` (e.g. ``west init -h``). + +.. _west-init: + +``west init`` +============= + +This command creates a west workspace. It can be used in two ways: + +1. Cloning a new manifest repository from a remote URL +2. Creating a workspace around an existing local manifest repository + +**Option 1**: to clone a new manifest repository from a remote URL, use: + +.. code-block:: none + + west init [-m URL] [--mr REVISION] [--mf FILE] [directory] + +The new workspace is created in the given :file:`directory`, creating a new +:file:`.west` inside this directory. You can give the manifest URL using +the ``-m`` switch, the initial revision to check out using ``--mr``, and +the location of the manifest file within the repository using ``--mf``. + +For example, running: + +.. code-block:: shell + + west init -m https://github.com/zephyrproject-rtos/zephyr --mr v1.14.0 zp + +would clone the upstream official zephyr repository into :file:`zp/zephyr`, +and check out the ``v1.14.0`` release. This command creates +:file:`zp/.west`, and set the ``manifest.path`` :ref:`configuration option +` to ``zephyr`` to record the location of the manifest +repository in the workspace. The default manifest file location is used. + +The ``-m`` option defaults to +``https://github.com/zephyrproject-rtos/zephyr``. The ``--mr`` option +defaults to ``master``. The ``--mf`` option defaults to ``west.yml``. If no +``directory`` is given, the current working directory is used. + +**Option 2**: to create a workspace around an existing local manifest +repository, use: + +.. code-block:: none + + west init -l [--mf FILE] directory + +This creates :file:`.west` **next to** :file:`directory` in the file +system, and sets ``manifest.path`` to ``directory``. + +As above, ``--mf`` defaults to ``west.yml``. + +The ``west init`` command does not clone any of the projects defined in the +manifest file, regardless of whether ``-l`` is given. To do that, use +``west update``. + +.. _west-update: + +``west update`` +--------------- + +This command clones and updates the projects specified in the :term:`west +manifest` file. + +.. code-block:: none + + west update [-h] [--stats] [-f {always,smart}] [-k] [-r] [PROJECT ...] + +By default, this command: + +#. Parses the manifest file, usually :file:`west.yml` +#. Clones any project repositories that are not already present locally +#. Fetches any project revisions which are not already pulled from the + remote +#. Sets each project's :ref:`manifest-rev ` branch to the + revision specified for that project in the manifest file +#. Checks out each ``manifest-rev`` in local working trees, as `detached + HEADs `_ + +To operate on a subset of projects only, specify them using the ``PROJECT`` +positional arguments, which can be either project names as given in the +manifest file, or paths to the local project clones. + +To force this command to fetch from project remotes even if the revisions +appear to be available locally, either use ``--fetch always`` or set the +``update.fetch`` :ref:`configuration option ` to ``"always"``. + +For safety, ``west update`` uses ``git checkout --detach`` to check out a +detached ``HEAD`` at the manifest revision for each updated project, +leaving behind any branches which were already checked out. This is +typically a safe operation that will not modify any of your local branches. + +If you would rather rebase any locally checked out branches instead, use +the ``-r`` (``--rebase``) option. + +If you would like ``west update`` to keep local branches checked out as +long as they point to commits that are descendants of the new +``manifest-rev``, use the ``-k`` (``--keep-descendants``) option. + +.. _west-multi-repo-misc: + +Other Repository Management Commands +==================================== + +West has a few more commands for managing the repositories in the +workspace, which are summarized here. Run ``west -h`` for +detailed help. + +- ``west list``: print a line of information about each project in the + manifest, according to a format string +- ``west manifest``: manage the manifest file. See :ref:`west-manifest-cmd`. +- ``west diff``: run ``git diff`` in local project repositories +- ``west status``: run ``git status`` in local project repositories +- ``west forall``: run an arbitrary command in local project repositories + +Additional Commands +=================== + +Finally, here is a summary of other built-in commands. + +- ``west config``: get or set :ref:`configuration options ` +- ``west topdir``: print the top level directory of the west workspace +- ``west help``: get help about a command, or print information about all + commands in the workspace, including :ref:`west-extensions` + +.. _west-topologies: Topologies supported ******************** @@ -250,156 +460,6 @@ v2.2.0 and its modules, then add the ``app1`` and ``app2`` projects: You can also do this "by hand" by copy/pasting :file:`zephyr/west.yml` as shown :ref:`above ` for the T2 topology, with the same caveats. -.. _west-struct: - -West Structure -************** - -West's code is distributed via PyPI in a Python package named ``west``. See -:ref:`west-apis` for API documentation. - -This distribution also includes a launcher executable, also named ``west``. -When west is installed, the launcher is placed by :file:`pip3` somewhere in the -user's filesystem (exactly where depends on the operating system, but should be -on the ``PATH`` :ref:`environment variable `). This launcher is the -command-line entry point. - -.. _west-manifest-rev: - -The ``manifest-rev`` branch -*************************** - -West creates a branch named ``manifest-rev`` in each project, pointing to the -commit the project's revision resolves to. The branch is updated whenever -project data is fetched by ``west update``. Other multi-repo commands also use -``manifest-rev`` as a reference for the upstream revision as of the most recent -update. See :ref:`west-multi-repo-cmds`, below, for more information. - -``manifest-rev`` is a normal Git branch, but if you delete or otherwise modify -it, west will recreate and/or reset it as if with ``git reset --hard`` on the -next update (though ``git update-ref`` is used internally). For this reason, it -is normally a **bad idea to modify it yourself**. ``manifest-rev`` was added to -allow SHAs as project revisions in the manifest, and to give a consistent -reference for the current upstream revision regardless of how the manifest -changes over time. - -.. note:: - - West does not create a ``manifest-rev`` branch in the manifest repository, - since west does not manage the manifest repository's branches or revisions. - -.. _west-multi-repo-cmds: - -Multi-Repo Commands -******************* - -This section gives a quick overview of the multi-repo commands, split up by -functionality. Some commands loosely mimic the corresponding Git command, but -in a multi-repo context (e.g. ``west diff`` shows local changes on all -repositories). - -Project arguments can be the names of projects in the manifest, or (as -fallback) paths to them. Omitting project arguments to commands which accept a -list of projects (such as ``west list``, ``west forall``, etc.) usually -defaults to using all projects in the manifest file plus the manifest -repository itself. - -For help on individual commands, run ``west -h`` (e.g. ``west diff --h``). - -Main Commands -============= - -The ``west init`` and ``west update`` multi-repo commands are the most -important to understand. - -- ``west init [-l] [-m URL] [--mr REVISION] [PATH]``: create a west - workspace in directory :file:`PATH` (i.e. :file:`.west` etc. will be - created there). If the ``PATH`` argument is not given, the current working - directory is used. This command does not clone any of the projects in the - manifest; that is done the next time ``west update`` is run. - - This command can be invoked in two ways: - - 1. If you already have a local clone of the zephyr repository and want to - create a west workspace around it, you can use the ``-l`` switch to - pass its path to west, as in: ``west init -l path/to/zephyr``. This is - the only reason to use ``-l``. - - 2. Otherwise, omit ``-l`` to create a new workspace from a remote manifest - repository. You can give the manifest URL using the ``-m`` switch, and its - revision using ``--mr``. For example, invoking west with: ``west init -m - https://github.com/zephyrproject-rtos/zephyr --mr v1.15.0`` would clone - the upstream official zephyr repository at the tagged release v1.15.0 - (``-m`` defaults to https://github.com/zephyrproject-rtos/zephyr, and - the ``-mr`` default is overridden to ``v1.15.0``). - -- ``west update [--fetch {always,smart}] [--rebase] [--keep-descendants] - [PROJECT ...]``: clone and update the specified projects based - on the current :term:`west manifest`. - - By default, this command: - - #. Parses the manifest file, :file:`west.yml` - #. Clones any project repositories that are not already present locally - #. Fetches any project revisions in the manifest file which are not already - pulled from the remote - #. Sets each project's :ref:`manifest-rev ` branch to the - current manifest revision - #. Checks out those revisions in local working trees - - To operate on a subset of projects only, specify them using the ``PROJECT`` - positional arguments, which can be either project names as given in the - manifest file, or paths to the local project clones. - - To force this command to fetch from project remotes even if the revisions - appear to be available locally, either use ``--fetch always`` or set the - ``update.fetch`` :ref:`configuration option ` to ``"always"``. - - For safety, ``west update`` uses ``git checkout --detach`` to check out a - detached ``HEAD`` at the manifest revision for each updated project, leaving - behind any branches which were already checked out. This is typically a safe - operation that will not modify any of your local branches. See the help for - the ``--rebase`` / ``-r`` and ``--keep-descendants`` / ``-k`` options for - ways to influence this. - -.. _west-multi-repo-misc: - -Miscellaneous Commands -====================== - -West has a few more commands for managing the multi-repo, which are briefly -discussed here. Run ``west -h`` for detailed help. - -- ``west forall -c COMMAND [PROJECT ...]``: Runs the shell command ``COMMAND`` - within the top-level repository directory of each of the specified projects - (default: all cloned projects). If ``COMMAND`` consists of more than one - word, it must be quoted to prevent it from being split up by the shell. - - To run an arbitrary Git command in each project, use something like ``west - forall -c 'git --options'``. Note that ``west forall`` can be used - to run any command, though, not just Git commands. - -- ``west help ``: this is equivalent to ``west -h``. - -- ``west list [-f FORMAT] [PROJECT ...]``: Lists project information from the - manifest file, such as URL, revision, path, etc. The printed information can - be controlled using the ``-f`` option. - -- ``west manifest``: Manipulates manifest files. See :ref:`west-manifest-cmd`. - -- ``west manifest --validate``: Ensure the current manifest file is - well-formed. Print information about what's wrong and fail the process in - case of error. - -- ``west diff [PROJECT ...]``: Runs a multi-repo ``git diff`` - for the specified projects. - -- ``west status [PROJECT ...]``: Like ``west diff``, for - running ``git status``. - -- ``west topdir``: Prints the top directory of the west workspace. - Private repositories ******************** diff --git a/doc/guides/west/why.rst b/doc/guides/west/why.rst index e690b757..994ab3a5 100644 --- a/doc/guides/west/why.rst +++ b/doc/guides/west/why.rst @@ -36,6 +36,10 @@ The basic requirements are: Rationale for a custom tool *************************** +Some of west's features are similar to those provided by +`Git Submodules `_ and +Google's `repo `_. + Existing tools were considered during west's initial design and development. None were found suitable for Zephyr's requirements. In particular, these were examined in detail: From 1fde6a7ac893dca6ab891172b10e72949223f28e Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 8 Jan 2021 18:34:04 -0800 Subject: [PATCH 082/226] doc: west: add note about west update --keep-descendants option The previous and short description wasn't enough for me to understand the interesting trade-off of --keep-descendants, thanks to @mbolivar-nordic for clarifying this on Slack. For reference this option was added in west commit 11b8588303 part of https://github.com/zephyrproject-rtos/west/pull/165/ Signed-off-by: Marc Herbert --- doc/guides/west/repo-tool.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index de6fa452..2e8cccb4 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -257,6 +257,28 @@ If you would like ``west update`` to keep local branches checked out as long as they point to commits that are descendants of the new ``manifest-rev``, use the ``-k`` (``--keep-descendants``) option. +.. note:: + + ``west update --rebase`` will fail in projects that have git conflicts + between your branch and new commits brought in by the manifest. You + should immediately resolve these conflicts as you usually do with + ``git``, or you can use ``git -C rebase --abort`` to + ignore incoming changes for the moment. + + With a clean working tree, a plain ``west update`` never fails + because it does not try to hold on to your commits and simply + leaves them aside. + + ``west update --keep-descendants`` offers an intermediate option that + never fails either but does not treat all projects the same: + + - in projects where your branch diverged from the incoming commits, it + does not even try to rebase and leaves your branches behind just like a + plain ``west update`` does; + - in all other projects where no rebase or merge is needed it keeps + your branches in place. + + .. _west-multi-repo-misc: Other Repository Management Commands From 539ccb6a94f69bfa49171d0c7cd5263547d80d84 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 26 Jan 2021 19:40:31 +0100 Subject: [PATCH 083/226] doc: west: Fix config overrides Fix the documentation of the usage of --*-file, which were renamed from --kernel-*. Fixes #31630. Signed-off-by: Carles Cufi --- doc/guides/west/build-flash-debug.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 59ad249c..47bcd16c 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -392,14 +392,14 @@ Configuration Overrides The CMake cache contains default values West uses while flashing, such as where the board directory is on the file system, the path to the -kernel binaries to flash in several formats, and more. You can +zephyr binaries to flash in several formats, and more. You can override any of this configuration at runtime with additional options. For example, to override the HEX file containing the Zephyr image to flash (assuming your runner expects a HEX file), but keep other flash configuration at default values:: - west flash --kernel-hex path/to/some/other.hex + west flash --hex-file path/to/some/other.hex The ``west flash -h`` output includes a complete list of overrides supported by all runners. @@ -489,15 +489,15 @@ Configuration Overrides The CMake cache contains default values West uses for debugging, such as where the board directory is on the file system, the path to the -kernel binaries containing symbol tables, and more. You can override +zephyr binaries containing symbol tables, and more. You can override any of this configuration at runtime with additional options. For example, to override the ELF file containing the Zephyr binary and symbol tables (assuming your runner expects an ELF file), but keep other debug configuration at default values:: - west debug --kernel-elf path/to/some/other.elf - west debugserver --kernel-elf path/to/some/other.elf + west debug --elf-file path/to/some/other.elf + west debugserver --elf-file path/to/some/other.elf The ``west debug -h`` output includes a complete list of overrides supported by all runners. From 352eac6db161e4a1f2754f03f33ae74156568dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 11 Jan 2021 13:41:35 -0800 Subject: [PATCH 084/226] doc: west update can create loose commits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Try to spell out the implications of that a bit more clearly. Suggested-by: Marc Herbert Signed-off-by: Martí Bolívar --- doc/guides/west/repo-tool.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 2e8cccb4..e2acbb98 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -250,6 +250,13 @@ detached ``HEAD`` at the manifest revision for each updated project, leaving behind any branches which were already checked out. This is typically a safe operation that will not modify any of your local branches. +However, if you had added some local commits onto a previously detached +``HEAD`` checked out by west, then git will warn you that you've left +behind some commits which are no longer referred to by any branch. These +may be garbage-collected and lost at some point in the future. To avoid +this if you have local commits in the project, make sure you have a local +branch checked out before running ``west update``. + If you would rather rebase any locally checked out branches instead, use the ``-r`` (``--rebase``) option. From 56ecd5d515c1a6c003b2c81b36544fffe00ebddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 13 Jan 2021 12:00:04 -0800 Subject: [PATCH 085/226] doc: west: add manifest.file config option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I never added documentation for this option; whoops. Signed-off-by: Martí Bolívar --- doc/guides/west/config.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index 3079d7dc..dd00ed75 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -135,6 +135,10 @@ commands are documented in the pages for those commands. stdout is a terminal. * - ``commands.allow_extensions`` - Boolean, default ``true``, disables :ref:`west-extensions` if ``false`` + * - ``manifest.file`` + - String, default ``west.yml``. Relative path from the manifest repository + root directory to the manifest file used by ``west init`` and other + commands which parse the manifest. * - ``manifest.path`` - String, relative path from the :term:`west workspace` root directory to the manifest repository used by ``west update`` and other commands From 2708bebd0d8c0566ef6ac823e3fbf66b4b0c3e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 11 Jan 2021 18:42:41 -0800 Subject: [PATCH 086/226] doc: re-work west update to prep for new features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The west update docs mix together the steps for updating a project with the set of projects that are being updated. This is inconvenient now that west 0.9 has a concept of inactive projects. Split the content into a part that describes *which* projects are updated, and a separate part that describes how *each* project is updated. Signed-off-by: Martí Bolívar --- doc/guides/west/repo-tool.rst | 57 ++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index e2acbb98..bc97fd72 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -226,24 +226,43 @@ manifest` file. west update [-h] [--stats] [-f {always,smart}] [-k] [-r] [PROJECT ...] -By default, this command: - -#. Parses the manifest file, usually :file:`west.yml` -#. Clones any project repositories that are not already present locally -#. Fetches any project revisions which are not already pulled from the - remote -#. Sets each project's :ref:`manifest-rev ` branch to the - revision specified for that project in the manifest file -#. Checks out each ``manifest-rev`` in local working trees, as `detached +**Which projects are updated:** + +By default, this command parses the manifest file, usually +:file:`west.yml`, and updates each project specified there. To operate on a +subset of projects only, give ``PROJECT`` argument(s). Each ``PROJECT`` is +either a project name as given in the manifest file, or a path that points +to the project within the workspace. + +**Project update procedure:** + +For each project that is updated, this command: + +#. Initializes a local Git repository for the project in the workspace, if + it does not already exist +#. Inspects the project's ``revision`` field in the manifest, and fetches + it from the remote if it is not already available locally +#. Sets the project's :ref:`manifest-rev ` branch to the + commit specified by the revision in the previous step. +#. Checks out ``manifest-rev`` in the local working copy as a `detached HEADs `_ -To operate on a subset of projects only, specify them using the ``PROJECT`` -positional arguments, which can be either project names as given in the -manifest file, or paths to the local project clones. +To avoid unnecessary fetches, ``west update`` will not fetch project +``revision`` values which are Git SHAs or tags that are already available +locally. This is the behavior when the ``-f`` (``--fetch``) option has its +default value, ``smart``. To force this command to fetch from project remotes +even if the revisions appear to be available locally, either use ``-f always`` +or set the ``update.fetch`` :ref:`configuration option ` to +``always``. SHAs may be given as unique prefixes as long as they are acceptable +to Git [#fetchall]_. -To force this command to fetch from project remotes even if the revisions -appear to be available locally, either use ``--fetch always`` or set the -``update.fetch`` :ref:`configuration option ` to ``"always"``. +If the project ``revision`` is a Git ref that is not a tag nor a SHA (i.e. +if the project is tracking a branch), ``west update`` always fetches, +regardless of ``-f`` and ``update.fetch``. + +Some branch names might look like short SHAs, like ``deadbeef``. You can +always disambiguate this situation by prefixing the ``revision`` value with +``refs/heads/``, e.g. ``revision: refs/heads/deadbeef``. For safety, ``west update`` uses ``git checkout --detach`` to check out a detached ``HEAD`` at the manifest revision for each updated project, @@ -605,3 +624,11 @@ update`` without entering your password in that same shell. .. _namespace package: https://www.python.org/dev/peps/pep-0420/ + +.. rubric:: Footnotes + +.. [#fetchall] + + West may fetch all refs from the Git server when given a SHA as a revision. + This is because some Git servers have historically not allowed fetching + SHAs directly. From bd0595ff66b1fe52032d9cfe3bdb9ef265c3a7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 7 Jan 2021 08:25:15 -0800 Subject: [PATCH 087/226] doc: west has moved to allowlist/blocklist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The west manifest import feature now uses the terms "allowlist" and "blocklist" instead of "whitelist" and "blacklist", respectively. The old terms are still supported by the tool for compatibility, but the docs for this feature are going to use the new terms exclusively. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 35968c23..7348d5b5 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -749,15 +749,15 @@ The ``import`` key can also contain a mapping with the following keys: - ``file``: Optional. The name of the manifest file or directory to import. This defaults to :file:`west.yml` if not present. -- ``name-whitelist``: Optional. If present, a name or sequence of project names +- ``name-allowlist``: Optional. If present, a name or sequence of project names to include. -- ``path-whitelist``: Optional. If present, a path or sequence of project paths +- ``path-allowlist``: Optional. If present, a path or sequence of project paths to match against. This is a shell-style globbing pattern, currently implemented with `pathlib`_. Note that this means case sensitivity is platform specific. -- ``name-blacklist``: Optional. Like ``name-whitelist``, but contains project +- ``name-blocklist``: Optional. Like ``name-allowlist``, but contains project names to exclude rather than include. -- ``path-blacklist``: Optional. Like ``path-whitelist``, but contains project +- ``path-blocklist``: Optional. Like ``path-allowlist``, but contains project paths to exclude rather than include. - ``path-prefix``: Optional (new in v0.8.0). If given, this will be prepended to the project's path in the workspace, as well as the paths of any imported @@ -768,12 +768,12 @@ The ``import`` key can also contain a mapping with the following keys: .. _pathlib: https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.match -Whitelists override blacklists if both are given. For example, if a project is -blacklisted by path, then whitelisted by name, it will still be imported. +Allowlists override blocklists if both are given. For example, if a project is +blocked by path, then allowed by name, it will still be imported. .. _west-manifest-ex3.1: -Example 3.1: Downstream with name whitelist +Example 3.1: Downstream with name allowlist ------------------------------------------- Here is a pair of manifest files, representing a mainline and a @@ -802,7 +802,7 @@ hosted at ``https://git.example.com/mainline/manifest``. - name: mainline url: https://git.example.com/mainline/manifest import: - name-whitelist: + name-allowlist: - mainline-app - lib2 - name: downstream-app @@ -831,16 +831,16 @@ An equivalent manifest in a single file would be: path: libraries/lib2 url: https://git.example.com/mainline/lib2 -If a whitelist had not been used, the ``lib`` project from the mainline +If an allowlist had not been used, the ``lib`` project from the mainline manifest would have been imported. .. _west-manifest-ex3.2: -Example 3.2: Downstream with path whitelist +Example 3.2: Downstream with path allowlist ------------------------------------------- -Here is an example showing how to whitelist mainline's libraries only, -using ``path-whitelist``. +Here is an example showing how to allowlist mainline's libraries only, +using ``path-allowlist``. .. code-block:: yaml @@ -863,7 +863,7 @@ using ``path-whitelist``. - name: mainline url: https://git.example.com/mainline/manifest import: - path-whitelist: libraries/* + path-allowlist: libraries/* - name: app url: https://git.example.com/downstream/app - name: lib3 @@ -892,10 +892,10 @@ An equivalent manifest in a single file would be: .. _west-manifest-ex3.3: -Example 3.3: Downstream with path blacklist +Example 3.3: Downstream with path blocklist ------------------------------------------- -Here's an example showing how to blacklist all vendor HALs from mainline by +Here's an example showing how to block all vendor HALs from mainline by common path prefix in the workspace, add your own version for the chip you're targeting, and keep everything else. @@ -927,7 +927,7 @@ you're targeting, and keep everything else. - name: mainline url: https://git.example.com/mainline/manifest import: - path-blacklist: modules/hals/* + path-blocklist: modules/hals/* - name: hal_foo path: modules/hals/foo url: https://git.example.com/downstream/hal_foo From 77c822ac07e0d05e1513c5588b1bd85bd35d904f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 20 Jan 2021 20:52:06 -0800 Subject: [PATCH 088/226] doc: west: add project groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a new feature that allows you to associate projects with groups, then force west to ignore a subset of the projects list by disabling project groups. This can be selectively overridden via configuration file to make west stop ignoring the projects within an individual workspace. An example use case is to define a project whose Git repository requires credentials to pull. Putting such a project in a group named "foo" and disabling group "foo" would make "west update" ignore the project unless the user specifically configures the workspace to allow "foo". After that, "west update" will pull the project as usual. Signed-off-by: Martí Bolívar --- doc/guides/west/config.rst | 6 + doc/guides/west/manifest.rst | 397 +++++++++++++++++++++++++++++++++- doc/guides/west/repo-tool.rst | 33 ++- 3 files changed, 424 insertions(+), 12 deletions(-) diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index dd00ed75..3e09fd7e 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -139,6 +139,12 @@ commands are documented in the pages for those commands. - String, default ``west.yml``. Relative path from the manifest repository root directory to the manifest file used by ``west init`` and other commands which parse the manifest. + * - ``manifest.group-filter`` + - String, default empty. A comma-separated list of project groups to + enable and disable within the workspace. Prefix enabled groups with + ``+`` and disabled groups with ``-``. For example, the value + ``"+foo,-bar"`` enables group ``foo`` and disables ``bar``. See + :ref:`west-manifest-groups`. * - ``manifest.path`` - String, relative path from the :term:`west workspace` root directory to the manifest repository used by ``west update`` and other commands diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 7348d5b5..17790c66 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -74,8 +74,8 @@ Notice the following important details: Manifest Files ************** -A west manifest is a YAML file named :file:`west.yml`. Manifests have a -top-level ``manifest`` section with some subsections, like this: +West manifests are YAML files. Manifests have a top-level ``manifest`` section +with some subsections, like this: .. code-block:: yaml @@ -86,6 +86,8 @@ top-level ``manifest`` section with some subsections, like this: # short names for project URLs (optional) projects: # a list of projects managed by west (mandatory) + group-filter: + # a list of project groups to enable or disable (optional) self: # configuration related to the manifest repository itself, # i.e. the repository containing west.yml (optional) @@ -95,10 +97,10 @@ In YAML terms, the manifest file contains a mapping, with a ``manifest`` key. Any other keys and their contents are ignored (west v0.5 also required a ``west`` key, but this is ignored starting with v0.6). -There are four subsections: ``defaults``, ``remotes``, ``projects``, and -``self``. In YAML terms, the value of the ``manifest`` key is also a mapping, -with these "subsections" as keys. Only ``projects`` is mandatory: this is the -list of repositories managed by west and their metadata. +The manifest contains subsections, like ``defaults``, ``remotes``, +``projects``, and ``self``. In YAML terms, the value of the ``manifest`` key is +also a mapping, with these "subsections" as keys. Only ``projects`` is +mandatory: this is the list of repositories managed by west and their metadata. We'll cover the ``remotes`` and ``projects`` subsections in detail first. @@ -219,7 +221,9 @@ The list of project keys and their usage follows. Sometimes we'll refer to the :ref:`west-extensions` for details. - ``import``: Optional. If ``true``, imports projects from manifest files in the given repository into the current manifest. See - :ref:`west-manifest-import` for more details. + :ref:`west-manifest-import` for details. +- ``groups``: Optional, a list of groups the project belongs to. See + :ref:`west-manifest-groups` for details. The ``defaults`` subsection can provide default values for project attributes. In particular, the default remote name and revision can be @@ -1179,6 +1183,385 @@ processed in this order: - If the value is a sequence, its elements are recursively imported in the order they appear. +.. _west-manifest-groups: + +Project Groups and Active Projects +********************************** + +You can use the ``groups`` and ``group-filter`` keys briefly described +:ref:`above ` to place projects into groups, and filter +which groups are enabled. These keys appear in the manifest like this: + +.. code-block:: yaml + + manifest: + projects: + - name: some-project + groups: ... + group-filter: ... + +You can enable or disable project groups using ``group-filter``. Projects whose +groups are all disabled are *inactive*; west essentially ignores inactive +projects unless explicitly requested not to. + +The next section introduces project groups; the following sections describe +:ref:`west-enabled-disabled-groups` and :ref:`west-active-inactive-projects`. +Finally, there are :ref:`west-project-group-examples`. + +Project Groups +============== + +Inside ``manifest: projects:``, you can add a project to one or more groups. +The ``groups`` key is a list of group names. Group names are strings. + +For example, in this manifest fragment: + +.. code-block:: yaml + + manifest: + projects: + - name: project-1 + groups: + - groupA + - name: project-2 + groups: + - groupB + - groupC + - name: project-3 + +The projects are in these groups: + +- ``project-1``: one group, named ``groupA`` +- ``project-2``: two groups, named ``groupB`` and ``groupC`` +- ``project-3``: no groups + +Project group names must not contain commas (,), colons (:), or whitespace. + +Group names must not begin with a dash (-) or the plus sign (+), but they may +contain these characters elsewhere in their names. For example, ``foo-bar`` and +``foo+bar`` are valid groups, but ``-foobar`` and ``+foobar`` are not. + +Group names are otherwise arbitrary strings. Group names are case sensitive. + +As a restriction, no project may use both ``import:`` and ``groups:``. (This +avoids some edge cases whose semantics are difficult to specify.) + +.. _west-enabled-disabled-groups: + +Enabled and Disabled Project Groups +=================================== + +You can enable or disable project groups in both your manifest file and +:ref:`west-config`. + +All groups are enabled by default. + +Within the manifest file, the top level ``manifest: group-filter:`` value can +be used to disable project groups. To disable a group, prefix its name with a +dash (-). For example, in this manifest fragment: + +.. code-block:: yaml + + manifest: + group-filter: [-groupA,-groupB] + +The groups named ``groupA`` and ``groupB`` are disabled by this +``group-filter`` value. + +The ``group-filter`` list is an ordinary YAML list, so you could have also +written this fragment like this: + +.. code-block:: yaml + + manifest: + group-filter: + - -groupA + - -groupB + +However, this syntax is harder to read and therefore discouraged. + +Although it's not an error to enable groups within ``manifest: group-filter:``, +like this: + +.. code-block:: yaml + + manifest: + ... + group-filter: [+groupA] + +doing so is redundant since groups are enabled by default. + +Only the **top level manifest file's** ``manifest: group-filter:`` value has +any effect. The ``manifest: group-filter:`` values in any +:ref:`imported manifests ` are ignored. + +In addition to the manifest file, you can control which groups are enabled and +disabled using the ``manifest.group-filter`` configuration option. This option +is a comma-separated list of groups to enable and/or disable. + +To enable a group, add its name to the list prefixed with ``+``. To disable a +group, add its name prefixed with ``-``. For example, setting +``manifest.group-filter`` to ``+groupA,-groupB`` enables ``groupA``, and +disables ``groupB``. + +The value of the configuration option overrides any data in the manifest file. +You can think of this as if the ``manifest.group-filter`` configuration option +is appended to the ``manifest: group-filter:`` list from YAML, with "last entry +wins" semantics. + +.. _west-active-inactive-projects: + +Active and Inactive Projects +============================ + +All projects are *active* by default. Projects with no groups are always +active. A project is *inactive* if all of its groups are disabled. This is the +only way to make a project inactive. + +Most west commands that operate on projects will ignore inactive projects by +default. For example, :ref:`west-update` when run without arguments will not +update inactive projects. As another example, running ``west list`` without +arguments will not print information for inactive projects. + +.. _west-project-group-examples: + +Project Group Examples +====================== + +This section contains example situations involving project groups and active +projects. The examples use both ``manifest: group-filter:`` YAML lists and +``manifest.group-filter`` configuration lists, to show how they work together. + +Note that the ``defaults`` and ``remotes`` data in the following manifests +isn't relevant except to make the examples complete and self-contained. + +Example 1: no disabled groups +----------------------------- + +The entire manifest file is: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + groups: + - groupA + - name: bar + groups: + - groupA + - groupB + - name: baz + + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com + +The ``manifest.group-filter`` configuration option is not set (you can ensure +this by running ``west config -D manifest.group-filter``). + +No groups are disabled, because all groups are enabled by default. Therefore, +all three projects (``foo``, ``bar``, and ``baz``) are active. Note that there +is no way to make project ``baz`` inactive, since it has no groups. + +Example 2: Disabling one group via manifest +------------------------------------------- + +The entire manifest file is: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + groups: + - groupA + - name: bar + groups: + - groupA + - groupB + + group-filter: [-groupA] + + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com + +The ``manifest.group-filter`` configuration option is not set (you can ensure +this by running ``west config -D manifest.group-filter``). + +Since ``groupA`` is disabled, project ``foo`` is inactive. Project ``bar`` is +active, because ``groupB`` is enabled. + +Example 3: Disabling multiple groups via manifest +------------------------------------------------- + +The entire manifest file is: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + groups: + - groupA + - name: bar + groups: + - groupA + - groupB + + group-filter: [-groupA,-groupB] + + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com + +The ``manifest.group-filter`` configuration option is not set (you can ensure +this by running ``west config -D manifest.group-filter``). + +Both ``foo`` and ``bar`` are inactive, because all of their groups are +disabled. + +Example 4: Disabling a group via configuration +---------------------------------------------- + +The entire manifest file is: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + groups: + - groupA + - name: bar + groups: + - groupA + - groupB + + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com + +The ``manifest.group-filter`` configuration option is set to ``-groupA`` (you +can ensure this by running ``west config manifest.group-filter -- -groupA``; +the extra ``--`` is required so the argument parser does not treat ``-groupA`` +as a command line option ``-g`` with value ``roupA``). + +Project ``foo`` is inactive because ``groupA`` has been disabled by the +``manifest.group-filter`` configuration option. Project ``bar`` is active +because ``groupB`` is enabled. + +Example 5: Overriding a disabled group via configuration +-------------------------------------------------------- + +The entire manifest file is: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + - name: bar + groups: + - groupA + - name: baz + groups: + - groupA + - groupB + + group-filter: [-groupA] + + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com + +The ``manifest.group-filter`` configuration option is set to ``+groupA`` (you +can ensure this by running ``west config manifest.group-filter +groupA``). + +In this case, ``groupA`` is enabled: the ``manifest.group-filter`` +configuration option has higher precedence than the ``manifest: group-filter: +[-groupA]`` content in the manifest file. + +Therefore, projects ``foo`` and ``bar`` are both active. + +Example 6: Overriding multiple disabled groups via configuration +---------------------------------------------------------------- + +The entire manifest file is: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + - name: bar + groups: + - groupA + - name: baz + groups: + - groupA + - groupB + + group-filter: [-groupA,-groupB] + + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com + +The ``manifest.group-filter`` configuration option is set to +``+groupA,+groupB`` (you can ensure this by running ``west config +manifest.group-filter "+groupA,+groupB"``). + +In this case, both ``groupA`` and ``groupB`` are enabled, because the +configuration value overrides the manifest file for both groups. + +Therefore, projects ``foo`` and ``bar`` are both active. + +Example 7: Disabling multiple groups via configuration +------------------------------------------------------ + +The entire manifest file is: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + - name: bar + groups: + - groupA + - name: baz + groups: + - groupA + - groupB + + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com + +The ``manifest.group-filter`` configuration option is set to +``-groupA,-groupB`` (you can ensure this by running ``west config +manifest.group-filter -- "-groupA,-groupB"``). + +In this case, both ``groupA`` and ``groupB`` are disabled. + +Therefore, projects ``foo`` and ``bar`` are both inactive. + .. _west-manifest-cmd: Manifest Command diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index bc97fd72..637a605d 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -224,15 +224,20 @@ manifest` file. .. code-block:: none - west update [-h] [--stats] [-f {always,smart}] [-k] [-r] [PROJECT ...] + west update [-f {always,smart}] [-k] [-r] + [--group-filter FILTER] [--stats] [PROJECT ...] **Which projects are updated:** By default, this command parses the manifest file, usually -:file:`west.yml`, and updates each project specified there. To operate on a -subset of projects only, give ``PROJECT`` argument(s). Each ``PROJECT`` is -either a project name as given in the manifest file, or a path that points -to the project within the workspace. +:file:`west.yml`, and updates each project specified there. +If your manifest uses :ref:`project groups `, then +only the active projects are updated. + +To operate on a subset of projects only, give ``PROJECT`` argument(s). Each +``PROJECT`` is either a project name as given in the manifest file, or a +path that points to the project within the workspace. If you specify +projects explicitly, they are updated regardless of whether they are active. **Project update procedure:** @@ -304,6 +309,24 @@ long as they point to commits that are descendants of the new - in all other projects where no rebase or merge is needed it keeps your branches in place. +**One-time project group manipulation:** + +The ``--group-filter`` option can be used to change which project groups +are enabled or disabled for the duration of a single ``west update`` command. +See :ref:`west-manifest-groups` for details on the project group feature. + +The ``west update`` command behaves as if the ``--group-filter`` option's +value were appended to the ``manifest.group-filter`` +:ref:`configuration option `. + +For example, running ``west update --group-filter=+foo,-bar`` would behave +the same way as if you had temporarily appended the string ``"+foo,-bar"`` +to the value of ``manifest.group-filter``, run ``west update``, then restored +``manifest.group-filter`` to its original value. + +Note that using the syntax ``--group-filter=VALUE`` instead of +``--group-filter VALUE`` avoids issues parsing command line options +if you just want to disable a single group, e.g. ``--group-filter=-bar``. .. _west-multi-repo-misc: From e3cede8e61d46db201b960107548e948ed1827c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 11 Jan 2021 16:29:10 -0800 Subject: [PATCH 089/226] doc: west: add submodules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit West 0.9, now with submodules! This is a new feature which allows you to incorporate a project's Git submodules into the workspace. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 82 +++++++++++++++++++++++++++++++++++ doc/guides/west/repo-tool.rst | 33 ++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 17790c66..f3bd6d39 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -224,6 +224,11 @@ The list of project keys and their usage follows. Sometimes we'll refer to the :ref:`west-manifest-import` for details. - ``groups``: Optional, a list of groups the project belongs to. See :ref:`west-manifest-groups` for details. +- ``submodules``: Optional. You can use this to make ``west update`` also + update `Git submodules`_ defined by the project. See + :ref:`west-manifest-submodules` for details. + +.. _Git submodules: https://git-scm.com/book/en/v2/Git-Tools-Submodules The ``defaults`` subsection can provide default values for project attributes. In particular, the default remote name and revision can be @@ -1562,6 +1567,83 @@ In this case, both ``groupA`` and ``groupB`` are disabled. Therefore, projects ``foo`` and ``bar`` are both inactive. +.. _west-manifest-submodules: + +Git Submodules in Projects +************************** + +You can use the ``submodules`` keys briefly described :ref:`above +` to force ``west update`` to also handle any `Git +submodules`_ configured in project's git repository. The ``submodules`` key can +appear inside ``projects``, like this: + +.. code-block:: YAML + + manifest: + projects: + - name: some-project + submodules: ... + +The ``submodules`` key can be a boolean or a list of mappings. We'll describe +these in order. + +Option 1: Boolean +================= + +This is the easiest way to use ``submodules``. + +If ``submodules`` is ``true`` as a ``projects`` attribute, ``west update`` will +recursively update the project's Git submodules whenever it updates the project +itself. If it's ``false`` or missing, it has no effect. + +For example, let's say you have a source code repository ``foo``, which has +some submodules, and you want ``west update`` to keep all of them them in sync, +along with another project named ``bar`` in the same workspace. + +You can do that with this manifest file: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + submodules: true + - name: bar + +Here, ``west update`` will initialize and update all submodules in ``foo``. If +``bar`` has any submodules, they are ignored, because ``bar`` does not have a +``submodules`` value. + +Option 2: List of mappings +========================== + +The ``submodules`` key may be a list of mappings. Each element in the list +defines the name of the submodule to update, and the path -- relative to the +project's absolute path in the workspace -- to use for the submodule. +The submodule will be updated recursively. + +For example, let's say you have a source code repository ``foo``, which has +many submodules, and you want ``west update`` to keep some but not all of them +in sync, along with another project named ``bar`` in the same workspace. + +You can do that with this manifest file: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + submodules: + - name: foo-first-sub + path: path/to/foo-first-sub + - name: foo-second-sub + path: path/to/foo-second-sub + - name: bar + +Here, ``west update`` will recursively initialize and update just the +submodules in ``foo`` with paths ``path/to/foo-first-sub`` and +``path/to/foo-second-sub``. Any submodules in ``bar`` are still ignored. + .. _west-manifest-cmd: Manifest Command diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index 637a605d..e995ce70 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -251,6 +251,9 @@ For each project that is updated, this command: commit specified by the revision in the previous step. #. Checks out ``manifest-rev`` in the local working copy as a `detached HEADs `_ +#. If the manifest file specifies a :ref:`submodules + ` key for the project, recursively updates + the project's submodules as described below. To avoid unnecessary fetches, ``west update`` will not fetch project ``revision`` values which are Git SHAs or tags that are already available @@ -328,6 +331,36 @@ Note that using the syntax ``--group-filter=VALUE`` instead of ``--group-filter VALUE`` avoids issues parsing command line options if you just want to disable a single group, e.g. ``--group-filter=-bar``. +**Submodule update procedure:** + +If a project in the manifest has a ``submodules`` key, the submodules are +updated as follows, depending on the value of the ``submodules`` key. + +If the project has ``submodules: true``, west runs one of the following in +the project repository, depending on whether you run ``west update`` +with the ``--rebase`` option or without it: + +.. code-block:: + + # without --rebase, e.g. "west update": + git submodule update init --checkout --recursive + + # with --rebase, e.g. "west update --rebase": + git submodule update init --rebase --recursive + +Otherwise, the project has ``submodules: ``. In this +case, west runs one of the following in the project repository for each +submodule path in the list, depending on whether you run ``west update`` +with the ``--rebase`` option or without it: + +.. code-block:: + + # without --rebase, e.g. "west update": + git submodule update init --checkout --recursive + + # with --rebase, e.g. "west update --rebase": + git submodule update init --rebase --recursive + .. _west-multi-repo-misc: Other Repository Management Commands From 701b8a2d09bf4958a311339f110b7a337e351164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 11 Jan 2021 16:35:00 -0800 Subject: [PATCH 090/226] doc: west: update schema version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit West 0.9 has a new schema version; document it and fix a missed update from 0.8. Whoops. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index f3bd6d39..a62142d1 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -307,8 +307,9 @@ manifest file schema that can parse this file's data: The pykwalify schema :file:`manifest-schema.yml` in the west source code repository is used to validate the manifest section. The current manifest -``version`` is 0.7, which corresponds to west version 0.7. This is the only -value this field can currently take. +``version`` is 0.9, which corresponds to west version 0.9. + +The ``version`` value may be 0.7, 0.8, or 0.9. If a later version of west, say version ``21.0``, includes changes to the manifest schema that cannot be parsed by west 0.7, then setting ``version: From 59a48d5e4f50fac7a4f1669dc504fdcd8ffa1162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 11 Jan 2021 18:12:22 -0800 Subject: [PATCH 091/226] doc: west: API changes for 0.9.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are minimal. Signed-off-by: Martí Bolívar --- doc/guides/west/west-apis.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 2bd3efc3..43b3bc29 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -265,6 +265,8 @@ Manifest and sub-objects .. versionadded:: 0.7.0 .. automethod:: as_frozen_yaml .. versionadded:: 0.7.0 + .. automethod:: is_active + .. versionadded:: 0.9.0 .. autoclass:: west.manifest.ImportFlag :members: @@ -285,6 +287,9 @@ Manifest and sub-objects .. versionadded:: 0.7.0 The *remote_name* and *name_and_path* attributes. + .. versionadded:: 0.9.0 + The *group_filter* and *submodules* attributes. + Constructor: .. automethod:: __init__ @@ -352,6 +357,10 @@ Manifest and sub-objects .. versionadded:: 0.6.0 +.. autoclass:: west.manifest.Submodule + +.. versionadded:: 0.9.0 + Exceptions ========== From 393942f5f4ea9ed0a650e56295e5c21840ffd5fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 7 Jan 2021 10:03:50 -0800 Subject: [PATCH 092/226] doc: west: release notes for 0.9.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main new features are submodule support and project groups. Signed-off-by: Martí Bolívar --- doc/guides/west/index.rst | 2 +- doc/guides/west/release-notes.rst | 65 +++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index fd0f1b38..9a484891 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -26,7 +26,7 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.8.x`` releases, and provide additional +The following pages document west's ``v0.9.x`` releases, and provide additional context about the tool. .. toctree:: diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 5062b0ad..6cc1d23b 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,6 +1,71 @@ West Release Notes ################## +v0.9.0 +****** + +.. warning:: + + The ``west config`` fix described below comes at a cost: any comments or + other manual edits in configuration files will be removed when setting a + configuration option via that command or the ``west.configuration`` API. + +New features: + +- West manifests now support :ref:`west-manifest-submodules`. This allows you + to clone `Git submodules + `_ into a west project + repository in addition to the project repository itself. + +- West manifests now support :ref:`west-manifest-groups`. Project groups can be + enabled and disabled to determine what projects are "active", and therefore + will be acted upon by the following commands: ``west update``, ``west list``, + ``west diff``, ``west status``, ``west forall``. + +- ``west update`` no longer updates inactive projects by default. It now + supports a ``--group-filter`` option which allows for one-time modifications + to the set of enabled and disabled project groups. + +- Running ``west list``, ``west diff``, ``west status``, or ``west forall`` + with no arguments does not print information for inactive projects by + default. If the user specifies a list of projects explicitly at the command + line, output for them is included regardless of whether they are active. + + These commands also now support ``--all`` arguments to include all + projects, even inactive ones. + +- ``west list`` now supports a ``{groups}`` format string key in its + ``--format`` argument. + +Bug fixes: + +- The ``west config`` command and ``west.configuration`` API did not correctly + store some configuration values, such as strings which contain commas. This + has been fixed; see `commit 36f3f91e + `_ + for details. + +- A manifest file with an empty ``manifest: self: path:`` value is invalid, but + west used to let it pass silently. West now rejects such manifests. + +- A bug affecting the behavior of the ``west init -l .`` command was fixed; see + `issue #435 `_. + +:ref:`API ` changes: + +- added ``west.manifest.Manifest.is_active()`` +- added ``west.manifest.Manifest.group_filter`` +- added ``submodules`` attribute to ``west.manifest.Project``, which has + newly added type ``west.manifest.Submodule`` + +Other changes: + +- The :ref:`west-manifest-import` feature now supports the terms ``allowlist`` + and ``blocklist`` instead of ``whitelist`` and ``blacklist``, respectively. + + The old terms are still supported for compatibility, but the documentation + has been updated to use the new ones exclusively. + v0.8.0 ****** From d432bd726bf2dac70bf0570e5c1213b0b474c55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 13 Jan 2021 18:22:05 -0800 Subject: [PATCH 093/226] doc: west reserves refs/west/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These Git refs are used by west as a scratch space. Let that be known, but don't make any other guarantees. Signed-off-by: Martí Bolívar --- doc/guides/west/repo-tool.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/repo-tool.rst index e995ce70..f5bffbf5 100644 --- a/doc/guides/west/repo-tool.rst +++ b/doc/guides/west/repo-tool.rst @@ -139,6 +139,15 @@ it. West does not create a ``manifest-rev`` branch in the manifest repository, since west does not manage the manifest repository's branches or revisions. +The ``refs/west/*`` Git refs +**************************** + +West also reserves all Git refs that begin with ``refs/west/`` (such as +``refs/west/foo``) for itself in local project repositories. Unlike +``manifest-rev``, these refs are not regular branches. West's behavior here is +an implementation detail; users should not rely on these refs existence or +behavior. + .. _west-built-in-cmds: Built-in Commands From 22f8ed061b24e737c52af7104df0afab4993265d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Sat, 6 Feb 2021 11:23:35 -0800 Subject: [PATCH 094/226] doc: clean up west index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the 'basics' page to basics.rst, adding a redirect for the old title. Rearrange some other index pages to improve the flow: - Put relatively stale content in moving-to-west.rst to the bottom. I expect pepole have either moved west or are choosing not to. - Promote the release notes page higher up, since that seems more important. Signed-off-by: Martí Bolívar --- doc/guides/west/{repo-tool.rst => basics.rst} | 0 doc/guides/west/index.rst | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename doc/guides/west/{repo-tool.rst => basics.rst} (100%) diff --git a/doc/guides/west/repo-tool.rst b/doc/guides/west/basics.rst similarity index 100% rename from doc/guides/west/repo-tool.rst rename to doc/guides/west/basics.rst diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 9a484891..eb09bf73 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -33,9 +33,9 @@ context about the tool. :maxdepth: 1 install.rst - moving-to-west.rst + release-notes.rst troubleshooting.rst - repo-tool.rst + basics.rst manifest.rst config.rst extensions.rst @@ -43,8 +43,8 @@ context about the tool. sign.rst zephyr-cmds.rst why.rst + moving-to-west.rst without-west.rst - release-notes.rst For details on west's Python APIs, see :ref:`west-apis`. From 27eee1994287d5f85d42a4c466e76206113130bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Sat, 6 Feb 2021 13:18:02 -0800 Subject: [PATCH 095/226] doc: west: move advanced content out of 'basics' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the documentation for west 0.9, the 'basics' page is completely out of control. Reorganize it so it fits in a few pages, moving many details out into other pages for the truly curious. As part of this, create new pages for built-in commands (built-in.rst) and esoteric details about workspaces (workspaces.rst). Signed-off-by: Martí Bolívar --- doc/guides/west/basics.rst | 753 +++++----------------------- doc/guides/west/built-in.rst | 255 ++++++++++ doc/guides/west/config.rst | 4 +- doc/guides/west/index.rst | 2 + doc/guides/west/install.rst | 19 + doc/guides/west/manifest.rst | 2 +- doc/guides/west/release-notes.rst | 6 +- doc/guides/west/troubleshooting.rst | 30 ++ doc/guides/west/why.rst | 4 +- doc/guides/west/workspaces.rst | 309 ++++++++++++ 10 files changed, 748 insertions(+), 636 deletions(-) create mode 100644 doc/guides/west/built-in.rst create mode 100644 doc/guides/west/workspaces.rst diff --git a/doc/guides/west/basics.rst b/doc/guides/west/basics.rst index f5bffbf5..132c707b 100644 --- a/doc/guides/west/basics.rst +++ b/doc/guides/west/basics.rst @@ -1,19 +1,16 @@ -.. _west-multi-repo: +.. _west-basics: Basics ###### -This page introduces west's basic concepts and built-in commands along with -references to further reading. - -.. _west-workspace: - -Introduction -************ +This page introduces west's basic concepts and provides references to further +reading. West's built-in commands allow you to work with *projects* (Git -repositories) under a common *workspace* directory. You can create a -workspace using the :ref:`west-init` command. +repositories) under a common *workspace* directory. + +Example workspace +***************** If you've followed the upstream Zephyr getting started guide, your workspace looks like this: @@ -32,668 +29,168 @@ workspace looks like this: ├── net-tools/ # .git/ project └── [ ... other projects ...] -Above, :file:`zephyrproject` is the name of the workspace's top level -directory, or *topdir*. (The name :file:`zephyrproject` is just an example --- it could be anything, like ``z``, ``my-zephyr-workspace``, etc.) - -The topdir contains the :file:`.west` directory. When west needs to find -the topdir, it searches for :file:`.west`, and uses its parent directory. -The search starts from the current working directory (and starts again from -the location in the :envvar:`ZEPHYR_BASE` environment variable as a -fallback if that fails). The file :file:`.west/config` is the workspace's -:ref:`local configuration file `. - -Every west workspace contains exactly one *manifest repository*, which is a -Git repository containing a *manifest file*. The location of the manifest -repository is given by the :ref:`manifest.path configuration option -` in the local configuration file. - -For upstream Zephyr, :file:`zephyr` is the manifest repository, but you can -configure west to use any Git repository in the workspace as the manifest -repository. The only requirement is that it contains a valid manifest file. -See :ref:`west-topologies` for information on other options, and -:ref:`west-manifests` for details on the manifest file format. - -The manifest file is a YAML file that defines *projects*, which are the -additional Git repositories in the workspace managed by west. The manifest -file is named :file:`west.yml` by default; this can be overridden using the -``manifest.file`` local configuration option. - -You use the :ref:`west-update` command to update the workspace's projects -based on the contents of the manifest file. The manifest file controls -things like where the project should be placed within the workspace, what -URL to clone it from if it's missing, and what Git revision should be -checked out locally. - -Projects can be located anywhere inside the workspace, but they may not -"escape" it. Project repositories need not be located in subdirectories of -the manifest repository or as immediate subdirectories of the topdir. -However, projects must have paths inside the workspace. (You may replace a -project's repository directory within the workspace with a symbolic link to -elsewhere on your computer, but west will not do this for you.) - -A workspace can contain additional Git repositories or other files and -directories not managed by west. West basically ignores anything in the -workspace except :file:`.west`, the manifest repository, and the projects -specified in the manifest file. - -For upstream Zephyr, ``tinycbor`` and ``net-tools`` are projects. They are -specified in the manifest file :file:`zephyr/west.yml`. This file specifies -that ``tinycbor`` is located in the :file:`modules/lib/tinycbor` directory -beneath the workspace topdir. By default, the Zephyr :ref:`build system -` uses west to get the locations of all the projects in the -workspace, so any code they contain can be used as :ref:`modules`. - -Finally, any repository managed by a west workspace (either the manifest -repository or any project repository) can define :ref:`west-extensions`. -Extensions are extra commands not built into west that you can run when -using that workspace. - -The zephyr repository uses this feature to provide Zephyr-specific commands -like :ref:`west build `. Defining these as extensions keeps -west's core agnostic to the specifics of any workspace's Zephyr version, -etc. - -.. _west-struct: - -Structure -********* - -West's code is distributed via PyPI in a Python package named ``west``. -This distribution includes a launcher executable, which is also named -``west`` (or ``west.exe`` on Windows). - -When west is installed, the launcher is placed by :file:`pip3` somewhere in -the user's filesystem (exactly where depends on the operating system, but -should be on the ``PATH`` :ref:`environment variable `). This -launcher is the command-line entry point to running both built-in commmands -like ``west init``, ``west update``, along with any extensions discovered -in the workspace. - -In addition to its command-line interface, you can also use west's Python -APIs directly. See :ref:`west-apis` for details. - -.. _west-manifest-rev: - -The ``manifest-rev`` branch -*************************** - -West creates and controls a Git branch named ``manifest-rev`` in each -project. This branch points to the revision that the manifest file -specified for the project at the time :ref:`west-update` was last run. -Other workspace management commands may use ``manifest-rev`` as a reference -point for the upstream revision as of this latest update. Among other -purposes, the ``manifest-rev`` branch allows the manifest file to use SHAs -as project revisions. - -Although ``manifest-rev`` is a normal Git branch, west will recreate and/or -reset it on the next update. For this reason, it is **dangerous** -to check it out or otherwise modify it yourself. For instance, any commits -you manually add to this branch may be lost the next time you run ``west -update``. Instead, check out a local branch with another name, and either -rebase it on top of a new ``manifest-rev``, or merge ``manifest-rev`` into -it. - -.. note:: - - West does not create a ``manifest-rev`` branch in the manifest repository, - since west does not manage the manifest repository's branches or revisions. - -The ``refs/west/*`` Git refs -**************************** - -West also reserves all Git refs that begin with ``refs/west/`` (such as -``refs/west/foo``) for itself in local project repositories. Unlike -``manifest-rev``, these refs are not regular branches. West's behavior here is -an implementation detail; users should not rely on these refs existence or -behavior. - -.. _west-built-in-cmds: - -Built-in Commands -***************** - -This section gives an overview of west's built-in commands. - -Some commands are related to Git commands with the same name, but operate -on the entire workspace. For example, ``west diff`` shows local changes in -multiple Git repositories in the workspace. - -Some commands take projects as arguments. These arguments can be project -names as specified in the manifest file, or (as a fallback) paths to them -on the local file system. Omitting project arguments to commands which -accept them (such as ``west list``, ``west forall``, etc.) usually defaults -to using all projects in the manifest file plus the manifest repository -itself. - -The following documentation does not exhaustively describe all commands. -For additional help, run ``west -h`` (e.g. ``west init -h``). - -.. _west-init: - -``west init`` -============= - -This command creates a west workspace. It can be used in two ways: - -1. Cloning a new manifest repository from a remote URL -2. Creating a workspace around an existing local manifest repository - -**Option 1**: to clone a new manifest repository from a remote URL, use: - -.. code-block:: none - - west init [-m URL] [--mr REVISION] [--mf FILE] [directory] - -The new workspace is created in the given :file:`directory`, creating a new -:file:`.west` inside this directory. You can give the manifest URL using -the ``-m`` switch, the initial revision to check out using ``--mr``, and -the location of the manifest file within the repository using ``--mf``. - -For example, running: - -.. code-block:: shell - - west init -m https://github.com/zephyrproject-rtos/zephyr --mr v1.14.0 zp - -would clone the upstream official zephyr repository into :file:`zp/zephyr`, -and check out the ``v1.14.0`` release. This command creates -:file:`zp/.west`, and set the ``manifest.path`` :ref:`configuration option -` to ``zephyr`` to record the location of the manifest -repository in the workspace. The default manifest file location is used. - -The ``-m`` option defaults to -``https://github.com/zephyrproject-rtos/zephyr``. The ``--mr`` option -defaults to ``master``. The ``--mf`` option defaults to ``west.yml``. If no -``directory`` is given, the current working directory is used. - -**Option 2**: to create a workspace around an existing local manifest -repository, use: - -.. code-block:: none - - west init -l [--mf FILE] directory - -This creates :file:`.west` **next to** :file:`directory` in the file -system, and sets ``manifest.path`` to ``directory``. - -As above, ``--mf`` defaults to ``west.yml``. - -The ``west init`` command does not clone any of the projects defined in the -manifest file, regardless of whether ``-l`` is given. To do that, use -``west update``. - -.. _west-update: - -``west update`` ---------------- - -This command clones and updates the projects specified in the :term:`west -manifest` file. - -.. code-block:: none - - west update [-f {always,smart}] [-k] [-r] - [--group-filter FILTER] [--stats] [PROJECT ...] - -**Which projects are updated:** - -By default, this command parses the manifest file, usually -:file:`west.yml`, and updates each project specified there. -If your manifest uses :ref:`project groups `, then -only the active projects are updated. - -To operate on a subset of projects only, give ``PROJECT`` argument(s). Each -``PROJECT`` is either a project name as given in the manifest file, or a -path that points to the project within the workspace. If you specify -projects explicitly, they are updated regardless of whether they are active. - -**Project update procedure:** - -For each project that is updated, this command: - -#. Initializes a local Git repository for the project in the workspace, if - it does not already exist -#. Inspects the project's ``revision`` field in the manifest, and fetches - it from the remote if it is not already available locally -#. Sets the project's :ref:`manifest-rev ` branch to the - commit specified by the revision in the previous step. -#. Checks out ``manifest-rev`` in the local working copy as a `detached - HEADs `_ -#. If the manifest file specifies a :ref:`submodules - ` key for the project, recursively updates - the project's submodules as described below. - -To avoid unnecessary fetches, ``west update`` will not fetch project -``revision`` values which are Git SHAs or tags that are already available -locally. This is the behavior when the ``-f`` (``--fetch``) option has its -default value, ``smart``. To force this command to fetch from project remotes -even if the revisions appear to be available locally, either use ``-f always`` -or set the ``update.fetch`` :ref:`configuration option ` to -``always``. SHAs may be given as unique prefixes as long as they are acceptable -to Git [#fetchall]_. - -If the project ``revision`` is a Git ref that is not a tag nor a SHA (i.e. -if the project is tracking a branch), ``west update`` always fetches, -regardless of ``-f`` and ``update.fetch``. - -Some branch names might look like short SHAs, like ``deadbeef``. You can -always disambiguate this situation by prefixing the ``revision`` value with -``refs/heads/``, e.g. ``revision: refs/heads/deadbeef``. - -For safety, ``west update`` uses ``git checkout --detach`` to check out a -detached ``HEAD`` at the manifest revision for each updated project, -leaving behind any branches which were already checked out. This is -typically a safe operation that will not modify any of your local branches. - -However, if you had added some local commits onto a previously detached -``HEAD`` checked out by west, then git will warn you that you've left -behind some commits which are no longer referred to by any branch. These -may be garbage-collected and lost at some point in the future. To avoid -this if you have local commits in the project, make sure you have a local -branch checked out before running ``west update``. - -If you would rather rebase any locally checked out branches instead, use -the ``-r`` (``--rebase``) option. - -If you would like ``west update`` to keep local branches checked out as -long as they point to commits that are descendants of the new -``manifest-rev``, use the ``-k`` (``--keep-descendants``) option. - -.. note:: - - ``west update --rebase`` will fail in projects that have git conflicts - between your branch and new commits brought in by the manifest. You - should immediately resolve these conflicts as you usually do with - ``git``, or you can use ``git -C rebase --abort`` to - ignore incoming changes for the moment. - - With a clean working tree, a plain ``west update`` never fails - because it does not try to hold on to your commits and simply - leaves them aside. - - ``west update --keep-descendants`` offers an intermediate option that - never fails either but does not treat all projects the same: - - - in projects where your branch diverged from the incoming commits, it - does not even try to rebase and leaves your branches behind just like a - plain ``west update`` does; - - in all other projects where no rebase or merge is needed it keeps - your branches in place. - -**One-time project group manipulation:** - -The ``--group-filter`` option can be used to change which project groups -are enabled or disabled for the duration of a single ``west update`` command. -See :ref:`west-manifest-groups` for details on the project group feature. - -The ``west update`` command behaves as if the ``--group-filter`` option's -value were appended to the ``manifest.group-filter`` -:ref:`configuration option `. - -For example, running ``west update --group-filter=+foo,-bar`` would behave -the same way as if you had temporarily appended the string ``"+foo,-bar"`` -to the value of ``manifest.group-filter``, run ``west update``, then restored -``manifest.group-filter`` to its original value. - -Note that using the syntax ``--group-filter=VALUE`` instead of -``--group-filter VALUE`` avoids issues parsing command line options -if you just want to disable a single group, e.g. ``--group-filter=-bar``. - -**Submodule update procedure:** - -If a project in the manifest has a ``submodules`` key, the submodules are -updated as follows, depending on the value of the ``submodules`` key. - -If the project has ``submodules: true``, west runs one of the following in -the project repository, depending on whether you run ``west update`` -with the ``--rebase`` option or without it: - -.. code-block:: - - # without --rebase, e.g. "west update": - git submodule update init --checkout --recursive - - # with --rebase, e.g. "west update --rebase": - git submodule update init --rebase --recursive - -Otherwise, the project has ``submodules: ``. In this -case, west runs one of the following in the project repository for each -submodule path in the list, depending on whether you run ``west update`` -with the ``--rebase`` option or without it: - -.. code-block:: - - # without --rebase, e.g. "west update": - git submodule update init --checkout --recursive - - # with --rebase, e.g. "west update --rebase": - git submodule update init --rebase --recursive - -.. _west-multi-repo-misc: - -Other Repository Management Commands -==================================== - -West has a few more commands for managing the repositories in the -workspace, which are summarized here. Run ``west -h`` for -detailed help. - -- ``west list``: print a line of information about each project in the - manifest, according to a format string -- ``west manifest``: manage the manifest file. See :ref:`west-manifest-cmd`. -- ``west diff``: run ``git diff`` in local project repositories -- ``west status``: run ``git status`` in local project repositories -- ``west forall``: run an arbitrary command in local project repositories +.. _west-workspace: -Additional Commands -=================== +Workspace concepts +****************** -Finally, here is a summary of other built-in commands. +Here are the basic concepts you should understand about this structure. +Additional details are in :ref:`west-workspaces`. -- ``west config``: get or set :ref:`configuration options ` -- ``west topdir``: print the top level directory of the west workspace -- ``west help``: get help about a command, or print information about all - commands in the workspace, including :ref:`west-extensions` +topdir + Above, :file:`zephyrproject` is the name of the workspace's top level + directory, or *topdir*. (The name :file:`zephyrproject` is just an example + -- it could be anything, like ``z``, ``my-zephyr-workspace``, etc.) -.. _west-topologies: + You'll typically create the topdir and a few other files and directories + using :ref:`west init `. -Topologies supported -******************** +.west directory + The topdir contains the :file:`.west` directory. When west needs to find + the topdir, it searches for :file:`.west`, and uses its parent directory. + The search starts from the current working directory (and starts again from + the location in the :envvar:`ZEPHYR_BASE` environment variable as a + fallback if that fails). -The following are example source code topologies supported by west. +configuration file + The file :file:`.west/config` is the workspace's :ref:`local configuration + file `. -- T1: star topology, zephyr is the manifest repository -- T2: star topology, a Zephyr application is the manifest repository -- T3: forest topology, freestanding manifest repository +manifest repository + Every west workspace contains exactly one *manifest repository*, which is a + Git repository containing a *manifest file*. The location of the manifest + repository is given by the :ref:`manifest.path configuration option + ` in the local configuration file. -T1: Star topology, zephyr is the manifest repository -==================================================== + For upstream Zephyr, :file:`zephyr` is the manifest repository, but you can + configure west to use any Git repository in the workspace as the manifest + repository. The only requirement is that it contains a valid manifest file. + See :ref:`west-topologies` for information on other options, and + :ref:`west-manifests` for details on the manifest file format. -- The zephyr repository acts as the central repository and specifies - its :ref:`modules` in its :file:`west.yml` -- Analogy with existing mechanisms: Git submodules with zephyr as the - super-project +manifest file + The manifest file is a YAML file that defines *projects*, which are the + additional Git repositories in the workspace managed by west. The manifest + file is named :file:`west.yml` by default; this can be overridden using the + ``manifest.file`` local configuration option. -This is the default. See :ref:`west-workspace` for how mainline Zephyr is an -example of this topology. + You use the :ref:`west update ` command to update the + workspace's projects based on the contents of the manifest file. -.. _west-t2: +projects + Projects are Git repositories managed by west. Projects are defined in the + manifest file and can be located anywhere inside the workspace. In the above + example workspace, ``tinycbor`` and ``net-tools`` are projects. -T2: Star topology, application is the manifest repository -========================================================= + By default, the Zephyr :ref:`build system ` uses west to get + the locations of all the projects in the workspace, so any code they contain + can be used as :ref:`modules`. -- Useful for those focused on a single application -- A repository containing a Zephyr application acts as the central repository - and names other projects required to build it in its :file:`west.yml`. This - includes the zephyr repository and any modules. -- Analogy with existing mechanisms: Git submodules with the application as - the super-project, zephyr and other projects as submodules +extensions + Any repository known to west (either the manifest repository or any project + repository) can define :ref:`west-extensions`. Extensions are extra west + commands you can run when using that workspace. -A workspace using this topology looks like this: + The zephyr repository uses this feature to provide Zephyr-specific commands + like :ref:`west build `. Defining these as extensions keeps + west's core agnostic to the specifics of any workspace's Zephyr version, + etc. -.. code-block:: none - - west-workspace/ - │ - ├── application/ # .git/ │ - │   ├── CMakeLists.txt │ - │   ├── prj.conf │ never modified by west - │   ├── src/ │ - │   │   └── main.c │ - │   └── west.yml # main manifest with optional import(s) and override(s) - │ │ - ├── modules/ - │   └── lib/ - │   └── tinycbor/ # .git/ project from either the main manifest or some import. - │ - └── zephyr/ # .git/ project - └── west.yml # This can be partially imported with lower precedence or ignored. - # Only the 'manifest-rev' version can be imported. - - -Here is an example :file:`application/west.yml` which uses -:ref:`west-manifest-import`, available since west 0.7, to import Zephyr v2.2.0 -and its modules into the application manifest file: - -.. code-block:: yaml - - # Example T2 west.yml, using manifest imports. - manifest: - remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos - projects: - - name: zephyr - remote: zephyrproject-rtos - revision: v2.2.0 - import: true - self: - path: application - -You can still selectively "override" individual Zephyr modules if you use -``import:`` in this way; see :ref:`west-manifest-ex1.3` for an example. - -Another way to do the same thing is to copy/paste :file:`zephyr/west.yml` -to :file:`application/west.yml`, adding an entry for the zephyr -project itself, like this: - -.. code-block:: yaml - - # Equivalent to the above, but with manually maintained Zephyr modules. - manifest: - remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos - defaults: - remote: zephyrproject-rtos - projects: - - name: zephyr - revision: v2.2.0 - west-commands: scripts/west-commands.yml - - name: net-tools - revision: some-sha-goes-here - path: tools/net-tools - # ... other Zephyr modules go here ... - self: - path: application - -(The ``west-commands`` is there for :ref:`west-build-flash-debug` and other -Zephyr-specific :ref:`west-extensions`. It's not necessary when using -``import``.) - -The main advantage to using ``import`` is not having to track the revisions of -imported projects separately. In the above example, using ``import`` means -Zephyr's :ref:`module ` versions are automatically determined from the -:file:`zephyr/west.yml` revision, instead of having to be copy/pasted (and -maintained) on their own. - -T3: Forest topology -=================== - -- Useful for those supporting multiple independent applications or downstream - distributions with no "central" repository -- A dedicated manifest repository which contains no Zephyr source code, - and specifies a list of projects all at the same "level" -- Analogy with existing mechanisms: Google repo-based source distribution - -A workspace using this topology looks like this: +ignored files + A workspace can contain additional Git repositories or other files and + directories not managed by west. West basically ignores anything in the + workspace except :file:`.west`, the manifest repository, and the projects + specified in the manifest file. -.. code-block:: none +west init and west update +************************* - west-workspace/ - ├── app1/ # .git/ project - │   ├── CMakeLists.txt - │   ├── prj.conf - │   └── src/ - │   └── main.c - ├── app2/ # .git/ project - │   ├── CMakeLists.txt - │   ├── prj.conf - │   └── src/ - │   └── main.c - ├── manifest-repo/ # .git/ never modified by west - │   └── west.yml # main manifest with optional import(s) and override(s) - ├── modules/ - │   └── lib/ - │   └── tinycbor/ # .git/ project from either the main manifest or - │ # frome some import - │ - └── zephyr/ # .git/ project - └── west.yml # This can be partially imported with lower precedence or ignored. - # Only the 'manifest-rev' version can be imported. - - -Here is an example T3 :file:`manifest-repo/west.yml` which uses -:ref:`west-manifest-import`, available since west 0.7, to import Zephyr -v2.2.0 and its modules, then add the ``app1`` and ``app2`` projects: - -.. code-block:: yaml - - manifest: - remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos - - name: your-git-server - url-base: https://git.example.com/your-company - defaults: - remote: your-git-server - projects: - - name: zephyr - remote: zephyrproject-rtos - revision: v2.2.0 - import: true - - name: app1 - revision: SOME_SHA_OR_BRANCH_OR_TAG - - name: app2 - revision: ANOTHER_SHA_OR_BRANCH_OR_TAG - self: - path: manifest-repo - -You can also do this "by hand" by copy/pasting :file:`zephyr/west.yml` -as shown :ref:`above ` for the T2 topology, with the same caveats. - -Private repositories -******************** - -You can use west to fetch from private repositories. There is nothing -west-specific about this. - -The ``west update`` command essentially runs ``git fetch YOUR_PROJECT_URL`` -when a project's ``manifest-rev`` branch must be updated to a newly fetched -commit. It's up to your environment to make sure the fetch succeeds. - -You can either enter the password manually or use any of the `credential -helpers built in to Git`_. Since Git has credential storage built in, there is -no need for a west-specific feature. - -The following sections cover common cases for running ``west update`` without -having to enter your password, as well as how to troubleshoot issues. - -.. _credential helpers built in to Git: - https://git-scm.com/docs/gitcredentials - -Fetching via HTTPS -================== - -On Windows when fetching from GitHub, recent versions of Git prompt you for -your GitHub password in a graphical window once, then store it for future use -(in a default installation). Passwordless fetching from GitHub should therefore -work "out of the box" on Windows after you have done it once. - -In general, you can store your credentials on disk using the "store" git -credential helper. See the `git-credential-store`_ manual page for details. - -To use this helper for all the repositories in your workspace, run: +The two most important workspace-related commands are ``west init`` and ``west +update``. -.. code-block:: shell +.. _west-init-basics: - west forall -c "git config credential.helper store" +``west init`` basics +-------------------- -To use this helper on just the projects ``foo`` and ``bar``, run: +This command creates a west workspace. -.. code-block:: shell +.. important:: - west forall -c "git config credential.helper store" foo bar + West doesn't change your manifest repository contents after ``west init`` is + run. Use ordinary Git commands to pull new versions, etc. -To use this helper by default on your computer, run: +You will typically run it once, like this: .. code-block:: shell - git config --global credential.helper store - -On GitHub, you can set up a `personal access token`_ to use in place of your -account password. (This may be required if your account has two-factor -authentication enabled, and may be preferable to storing your account password -in plain text even if two-factor authentication is disabed.) + west init -m https://github.com/zephyrproject-rtos/zephyr --mr v2.5.0 zephyrproject -If you don't want to store any credentials on the file system, you can store -them in memory temporarily using `git-credential-cache`_ instead. +This will: -.. _git-credential-store: - https://git-scm.com/docs/git-credential-store#_examples -.. _git-credential-cache: - https://git-scm.com/docs/git-credential-cache -.. _personal access token: - https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token +#. Create the topdir, :file:`zephyrproject`, along with + :file:`.west` and :file:`.west/config` inside it +#. Clone the manifest repository from + https://github.com/zephyrproject-rtos/zephyr, placing it into + :file:`zephyrproject/zephyr` +#. Check out the ``v2.5.0`` git tag in your local zephyr clone +#. Set ``manifest.path`` to ``zephyr`` in :file:`.west/config` +#. Set ``manifest.file`` to ``west.yml`` -Fetching via SSH -================ +Your workspace is now almost ready to use; you just need to run ``west update`` +to clone the rest of the projects into the workspace to finish. -If your SSH key has no password, fetching should just work. If it does have a -password, you can avoid entering it manually every time using `ssh-agent`_. +For more details, see :ref:`west-init`. -On GitHub, see `Connecting to GitHub with SSH`_ for details on configuration -and key creation. +.. _west-update-basics: -.. _ssh-agent: - https://www.ssh.com/ssh/agent -.. _Connecting to GitHub with SSH: - https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh +``west update`` basics +---------------------- -Troubleshooting -=============== +This command makes sure your workspace contains Git repositories matching the +projects in the manifest file. -One good way to troubleshoot fetching issues is to run ``west update`` in -verbose mode, like this: +.. important:: -.. code-block:: shell + Whenever you check out a different revision in your manifest repository, you + should run ``west update`` to make sure your workspace contains the + project repositories the new revision expects. - west -v update +The ``west update`` command reads the manifest file's contents by: -The output includes Git commands run by west and their outputs. Look for -something like this: +#. Finding the topdir. In the ``west init`` example above, that + means finding :file:`zephyrproject`. +#. Loading :file:`.west/config` in the topdir to read the ``manifest.path`` + (e.g. ``zephyr``) and ``manifest.file`` (e.g. ``west.yml``) options. +#. Loading the manifest file given by these options (e.g. + :file:`zephyrproject/zephyr/west.yml`). -.. code-block:: none +It then uses the manifest file to decide where missing projects should be +placed within the workspace, what URLs to clone them from, and what Git +revisions should be checked out locally. Project repositories which already +exist are updated in place by fetching and checking out their respective Git +revisions in the manifest file. - === updating your_project (path/to/your/project): - west.manifest: your_project: checking if cloned - [...other west.manifest logs...] - --- your_project: fetching, need revision SOME_SHA - west.manifest: running 'git fetch ... https://github.com/your-username/your_project ...' in /some/directory +For more details, see :ref:`west-update`. -The ``git fetch`` command example in the last line above is what needs to -succeed. Go to ``/some/directory``, copy/paste and run the entire ``git fetch`` -command, then debug from there using the documentation for your credential -storage helper. +Other built-in commands +*********************** -If you can get the ``git fetch`` command to run successfully without prompting -for a password when you run it directly, you will be able to run ``west -update`` without entering your password in that same shell. +See :ref:`west-built-in-cmds`. -.. _PyPI: - https://pypi.org/project/west/ +.. _west-zephyr-extensions: -.. _Zephyr issue #6770: - https://github.com/zephyrproject-rtos/zephyr/issues/6770 +Zephyr Extensions +***************** -.. _namespace package: - https://www.python.org/dev/peps/pep-0420/ +See the following pages for information on Zephyr's extension commands: -.. rubric:: Footnotes +- :ref:`west-build-flash-debug` +- :ref:`west-sign` +- :ref:`west-zephyr-ext-cmds` +- :ref:`west-shell-completion` -.. [#fetchall] +Troubleshooting +*************** - West may fetch all refs from the Git server when given a SHA as a revision. - This is because some Git servers have historically not allowed fetching - SHAs directly. +See :ref:`west-troubleshooting`. diff --git a/doc/guides/west/built-in.rst b/doc/guides/west/built-in.rst new file mode 100644 index 00000000..e5591ac3 --- /dev/null +++ b/doc/guides/west/built-in.rst @@ -0,0 +1,255 @@ +.. _west-built-in-cmds: + +Built-in commands +################# + +This page describes west's built-in commands, some of which were introduced in +:ref:`west-basics`, in more detail. + +Some commands are related to Git commands with the same name, but operate +on the entire workspace. For example, ``west diff`` shows local changes in +multiple Git repositories in the workspace. + +Some commands take projects as arguments. These arguments can be project +names as specified in the manifest file, or (as a fallback) paths to them +on the local file system. Omitting project arguments to commands which +accept them (such as ``west list``, ``west forall``, etc.) usually defaults +to using all projects in the manifest file plus the manifest repository +itself. + +For additional help, run ``west -h`` (e.g. ``west init -h``). + +.. _west-init: + +west init +********* + +This command creates a west workspace. It can be used in two ways: + +1. Cloning a new manifest repository from a remote URL +2. Creating a workspace around an existing local manifest repository + +**Option 1**: to clone a new manifest repository from a remote URL, use: + +.. code-block:: none + + west init [-m URL] [--mr REVISION] [--mf FILE] [directory] + +The new workspace is created in the given :file:`directory`, creating a new +:file:`.west` inside this directory. You can give the manifest URL using +the ``-m`` switch, the initial revision to check out using ``--mr``, and +the location of the manifest file within the repository using ``--mf``. + +For example, running: + +.. code-block:: shell + + west init -m https://github.com/zephyrproject-rtos/zephyr --mr v1.14.0 zp + +would clone the upstream official zephyr repository into :file:`zp/zephyr`, +and check out the ``v1.14.0`` release. This command creates +:file:`zp/.west`, and set the ``manifest.path`` :ref:`configuration option +` to ``zephyr`` to record the location of the manifest +repository in the workspace. The default manifest file location is used. + +The ``-m`` option defaults to +``https://github.com/zephyrproject-rtos/zephyr``. The ``--mr`` option +defaults to ``master``. The ``--mf`` option defaults to ``west.yml``. If no +``directory`` is given, the current working directory is used. + +**Option 2**: to create a workspace around an existing local manifest +repository, use: + +.. code-block:: none + + west init -l [--mf FILE] directory + +This creates :file:`.west` **next to** :file:`directory` in the file +system, and sets ``manifest.path`` to ``directory``. + +As above, ``--mf`` defaults to ``west.yml``. + +**Reconfiguring the workspace**: + +If you change your mind later, you are free to change ``manifest.path`` and +``manifest.file`` using :ref:`west-config-cmd` after running ``west init``. +Just be sure to run ``west update`` afterwards to update your workspace to +match the new manifest file. + +.. _west-update: + +west update +*********** + +.. code-block:: none + + west update [-f {always,smart}] [-k] [-r] + [--group-filter FILTER] [--stats] [PROJECT ...] + +**Which projects are updated:** + +By default, this command parses the manifest file, usually +:file:`west.yml`, and updates each project specified there. +If your manifest uses :ref:`project groups `, then +only the active projects are updated. + +To operate on a subset of projects only, give ``PROJECT`` argument(s). Each +``PROJECT`` is either a project name as given in the manifest file, or a +path that points to the project within the workspace. If you specify +projects explicitly, they are updated regardless of whether they are active. + +**Project update procedure:** + +For each project that is updated, this command: + +#. Initializes a local Git repository for the project in the workspace, if + it does not already exist +#. Inspects the project's ``revision`` field in the manifest, and fetches + it from the remote if it is not already available locally +#. Sets the project's :ref:`manifest-rev ` branch to the + commit specified by the revision in the previous step +#. Checks out ``manifest-rev`` in the local working copy as a `detached + HEAD `_ +#. If the manifest file specifies a :ref:`submodules + ` key for the project, recursively updates + the project's submodules as described below. + +To avoid unnecessary fetches, ``west update`` will not fetch project +``revision`` values which are Git SHAs or tags that are already available +locally. This is the behavior when the ``-f`` (``--fetch``) option has its +default value, ``smart``. To force this command to fetch from project remotes +even if the revisions appear to be available locally, either use ``-f always`` +or set the ``update.fetch`` :ref:`configuration option ` to +``always``. SHAs may be given as unique prefixes as long as they are acceptable +to Git [#fetchall]_. + +If the project ``revision`` is a Git ref that is neither a tag nor a SHA (i.e. +if the project is tracking a branch), ``west update`` always fetches, +regardless of ``-f`` and ``update.fetch``. + +Some branch names might look like short SHAs, like ``deadbeef``. West treats +these like SHAs. You can disambiguate by prefixing the ``revision`` value with +``refs/heads/``, e.g. ``revision: refs/heads/deadbeef``. + +For safety, ``west update`` uses ``git checkout --detach`` to check out a +detached ``HEAD`` at the manifest revision for each updated project, +leaving behind any branches which were already checked out. This is +typically a safe operation that will not modify any of your local branches. + +However, if you had added some local commits onto a previously detached +``HEAD`` checked out by west, then git will warn you that you've left +behind some commits which are no longer referred to by any branch. These +may be garbage-collected and lost at some point in the future. To avoid +this if you have local commits in the project, make sure you have a local +branch checked out before running ``west update``. + +If you would rather rebase any locally checked out branches instead, use +the ``-r`` (``--rebase``) option. + +If you would like ``west update`` to keep local branches checked out as +long as they point to commits that are descendants of the new +``manifest-rev``, use the ``-k`` (``--keep-descendants``) option. + +.. note:: + + ``west update --rebase`` will fail in projects that have git conflicts + between your branch and new commits brought in by the manifest. You + should immediately resolve these conflicts as you usually do with + ``git``, or you can use ``git -C rebase --abort`` to + ignore incoming changes for the moment. + + With a clean working tree, a plain ``west update`` never fails + because it does not try to hold on to your commits and simply + leaves them aside. + + ``west update --keep-descendants`` offers an intermediate option that + never fails either but does not treat all projects the same: + + - in projects where your branch diverged from the incoming commits, it + does not even try to rebase and leaves your branches behind just like a + plain ``west update`` does; + - in all other projects where no rebase or merge is needed it keeps + your branches in place. + +**One-time project group manipulation:** + +The ``--group-filter`` option can be used to change which project groups +are enabled or disabled for the duration of a single ``west update`` command. +See :ref:`west-manifest-groups` for details on the project group feature. + +The ``west update`` command behaves as if the ``--group-filter`` option's +value were appended to the ``manifest.group-filter`` +:ref:`configuration option `. + +For example, running ``west update --group-filter=+foo,-bar`` would behave +the same way as if you had temporarily appended the string ``"+foo,-bar"`` +to the value of ``manifest.group-filter``, run ``west update``, then restored +``manifest.group-filter`` to its original value. + +Note that using the syntax ``--group-filter=VALUE`` instead of +``--group-filter VALUE`` avoids issues parsing command line options +if you just want to disable a single group, e.g. ``--group-filter=-bar``. + +**Submodule update procedure:** + +If a project in the manifest has a ``submodules`` key, the submodules are +updated as follows, depending on the value of the ``submodules`` key. + +If the project has ``submodules: true``, west runs one of the following in +the project repository, depending on whether you run ``west update`` +with the ``--rebase`` option or without it: + +.. code-block:: + + # without --rebase, e.g. "west update": + git submodule update init --checkout --recursive + + # with --rebase, e.g. "west update --rebase": + git submodule update init --rebase --recursive + +Otherwise, the project has ``submodules: ``. In this +case, west runs one of the following in the project repository for each +submodule path in the list, depending on whether you run ``west update`` +with the ``--rebase`` option or without it: + +.. code-block:: + + # without --rebase, e.g. "west update": + git submodule update init --checkout --recursive + + # with --rebase, e.g. "west update --rebase": + git submodule update init --rebase --recursive + +.. _west-built-in-misc: + +Other project commands +********************** + +West has a few more commands for managing the projects in the +workspace, which are summarized here. Run ``west -h`` for +detailed help. + +- ``west list``: print a line of information about each project in the + manifest, according to a format string +- ``west manifest``: manage the manifest file. See :ref:`west-manifest-cmd`. +- ``west diff``: run ``git diff`` in local project repositories +- ``west status``: run ``git status`` in local project repositories +- ``west forall``: run an arbitrary command in local project repositories + +Other built-in commands +*********************** + +Finally, here is a summary of other built-in commands. + +- ``west config``: get or set :ref:`configuration options ` +- ``west topdir``: print the top level directory of the west workspace +- ``west help``: get help about a command, or print information about all + commands in the workspace, including :ref:`west-extensions` + +.. rubric:: Footnotes + +.. [#fetchall] + + West may fetch all refs from the Git server when given a SHA as a revision. + This is because some Git servers have historically not allowed fetching + SHAs directly. diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index 3e09fd7e..d1e2f660 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -56,8 +56,8 @@ settings, and so on. .. _west-config-cmd: -West ``config`` Command ------------------------ +west config +----------- The built-in ``config`` command can be used to get and set configuration values. You can pass ``west config`` the options ``--system``, ``--global``, or diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index eb09bf73..85f1c05b 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -36,6 +36,8 @@ context about the tool. release-notes.rst troubleshooting.rst basics.rst + built-in.rst + workspaces.rst manifest.rst config.rst extensions.rst diff --git a/doc/guides/west/install.rst b/doc/guides/west/install.rst index d116e3bd..5734ee83 100644 --- a/doc/guides/west/install.rst +++ b/doc/guides/west/install.rst @@ -24,6 +24,25 @@ binary and related files were installed. Once west is installed, you can use it to :ref:`clone the Zephyr repositories `. +.. _west-struct: + +Structure +********* + +West's code is distributed via PyPI in a Python package named ``west``. +This distribution includes a launcher executable, which is also named +``west`` (or ``west.exe`` on Windows). + +When west is installed, the launcher is placed by :file:`pip3` somewhere in +the user's filesystem (exactly where depends on the operating system, but +should be on the ``PATH`` :ref:`environment variable `). This +launcher is the command-line entry point to running both built-in commmands +like ``west init``, ``west update``, along with any extensions discovered +in the workspace. + +In addition to its command-line interface, you can also use west's Python +APIs directly. See :ref:`west-apis` for details. + .. _west-shell-completion: Enabling shell completion diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index a62142d1..250f76d5 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -6,7 +6,7 @@ West Manifests This page contains detailed information about west's multiple repository model, manifest files, and the ``west manifest`` command. For API documentation on the ``west.manifest`` module, see :ref:`west-apis-manifest`. For a more general -introduction and command overview, see :ref:`west-multi-repo`. +introduction and command overview, see :ref:`west-basics`. .. only:: html diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 6cc1d23b..1c807702 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -136,7 +136,7 @@ Additional user-visible changes: - The "west config" command can now be run outside of a workspace, e.g. to run ``west config --global section.key value`` to set a configuration option's value globally. -- There is a new :ref:`west topdir ` command, which +- There is a new :ref:`west topdir ` command, which prints the root directory of the current west workspace. - The ``west -vv init`` command now prints the git operations being performed, and their results. @@ -225,9 +225,9 @@ The user-visible features in this point release are: projects. All of them also now report a nonzero error code from the west process if any of these subprocesses fails (this was previously not true of ``west forall`` in particular). -- The :ref:`west manifest ` command also handles errors +- The :ref:`west manifest ` command also handles errors better. -- The :ref:`west list ` command now works even when the +- The :ref:`west list ` command now works even when the projects are not cloned, as long as its format string only requires information which can be read from the manifest file. It still fails if the format string requires data stored in the project repository, e.g. if it diff --git a/doc/guides/west/troubleshooting.rst b/doc/guides/west/troubleshooting.rst index 0d354df3..e01000c6 100644 --- a/doc/guides/west/troubleshooting.rst +++ b/doc/guides/west/troubleshooting.rst @@ -5,6 +5,36 @@ Troubleshooting West This page covers common issues with west and how to solve them. +``west update`` fetching failures +********************************* + +One good way to troubleshoot fetching issues is to run ``west update`` in +verbose mode, like this: + +.. code-block:: shell + + west -v update + +The output includes Git commands run by west and their outputs. Look for +something like this: + +.. code-block:: none + + === updating your_project (path/to/your/project): + west.manifest: your_project: checking if cloned + [...other west.manifest logs...] + --- your_project: fetching, need revision SOME_SHA + west.manifest: running 'git fetch ... https://github.com/your-username/your_project ...' in /some/directory + +The ``git fetch`` command example in the last line above is what needs to +succeed. Go to ``/some/directory``, copy/paste and run the entire ``git fetch`` +command, then debug from there using the documentation for your credential +storage helper. + +If you can get the ``git fetch`` command to run successfully without prompting +for a password when you run it directly, you will be able to run ``west +update`` without entering your password in that same shell. + "'west' is not recognized as an internal or external command, operable program or batch file.' ********************************************************************************************** diff --git a/doc/guides/west/why.rst b/doc/guides/west/why.rst index 994ab3a5..e1f51381 100644 --- a/doc/guides/west/why.rst +++ b/doc/guides/west/why.rst @@ -79,8 +79,8 @@ repositories in a standardized manner within the project: * Enforcement of modularization of the components * Out-of-tree development based on subsets of the supported boards and SoCs -See :ref:`west-multi-repo` for a detailed explanation of west's handling of -multiple repository management. +See :ref:`west-basics` for information on how west workspaces manage multiple +git repositories. .. _west-design-constraints: diff --git a/doc/guides/west/workspaces.rst b/doc/guides/west/workspaces.rst new file mode 100644 index 00000000..bc485e7b --- /dev/null +++ b/doc/guides/west/workspaces.rst @@ -0,0 +1,309 @@ +.. _west-workspaces: + +Workspaces +########## + +This page describes the *west workspace* concept introduced in +:ref:`west-basics` in more detail. + +.. _west-manifest-rev: + +The ``manifest-rev`` branch +*************************** + +West creates and controls a Git branch named ``manifest-rev`` in each +project. This branch points to the revision that the manifest file +specified for the project at the time :ref:`west-update` was last run. +Other workspace management commands may use ``manifest-rev`` as a reference +point for the upstream revision as of this latest update. Among other +purposes, the ``manifest-rev`` branch allows the manifest file to use SHAs +as project revisions. + +Although ``manifest-rev`` is a normal Git branch, west will recreate and/or +reset it on the next update. For this reason, it is **dangerous** +to check it out or otherwise modify it yourself. For instance, any commits +you manually add to this branch may be lost the next time you run ``west +update``. Instead, check out a local branch with another name, and either +rebase it on top of a new ``manifest-rev``, or merge ``manifest-rev`` into +it. + +.. note:: + + West does not create a ``manifest-rev`` branch in the manifest repository, + since west does not manage the manifest repository's branches or revisions. + +The ``refs/west/*`` Git refs +**************************** + +West also reserves all Git refs that begin with ``refs/west/`` (such as +``refs/west/foo``) for itself in local project repositories. Unlike +``manifest-rev``, these refs are not regular branches. West's behavior here is +an implementation detail; users should not rely on these refs' existence or +behavior. + +Private repositories +******************** + +You can use west to fetch from private repositories. There is nothing +west-specific about this. + +The ``west update`` command essentially runs ``git fetch YOUR_PROJECT_URL`` +when a project's ``manifest-rev`` branch must be updated to a newly fetched +commit. It's up to your environment to make sure the fetch succeeds. + +You can either enter the password manually or use any of the `credential +helpers built in to Git`_. Since Git has credential storage built in, there is +no need for a west-specific feature. + +The following sections cover common cases for running ``west update`` without +having to enter your password, as well as how to troubleshoot issues. + +.. _credential helpers built in to Git: + https://git-scm.com/docs/gitcredentials + +Fetching via HTTPS +================== + +On Windows when fetching from GitHub, recent versions of Git prompt you for +your GitHub password in a graphical window once, then store it for future use +(in a default installation). Passwordless fetching from GitHub should therefore +work "out of the box" on Windows after you have done it once. + +In general, you can store your credentials on disk using the "store" git +credential helper. See the `git-credential-store`_ manual page for details. + +To use this helper for all the repositories in your workspace, run: + +.. code-block:: shell + + west forall -c "git config credential.helper store" + +To use this helper on just the projects ``foo`` and ``bar``, run: + +.. code-block:: shell + + west forall -c "git config credential.helper store" foo bar + +To use this helper by default on your computer, run: + +.. code-block:: shell + + git config --global credential.helper store + +On GitHub, you can set up a `personal access token`_ to use in place of your +account password. (This may be required if your account has two-factor +authentication enabled, and may be preferable to storing your account password +in plain text even if two-factor authentication is disabed.) + +If you don't want to store any credentials on the file system, you can store +them in memory temporarily using `git-credential-cache`_ instead. + +.. _git-credential-store: + https://git-scm.com/docs/git-credential-store#_examples +.. _git-credential-cache: + https://git-scm.com/docs/git-credential-cache +.. _personal access token: + https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token + +Fetching via SSH +================ + +If your SSH key has no password, fetching should just work. If it does have a +password, you can avoid entering it manually every time using `ssh-agent`_. + +On GitHub, see `Connecting to GitHub with SSH`_ for details on configuration +and key creation. + +.. _ssh-agent: + https://www.ssh.com/ssh/agent +.. _Connecting to GitHub with SSH: + https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh + +Project locations +***************** + +Projects can be located anywhere inside the workspace, but they may not +"escape" it. + +In other words, project repositories need not be located in subdirectories of +the manifest repository or as immediate subdirectories of the topdir. However, +projects must have paths inside the workspace. + +You may replace a project's repository directory within the workspace with a +symbolic link to elsewhere on your computer, but west will not do this for you. + +.. _west-topologies: + +Topologies supported +******************** + +The following are example source code topologies supported by west. + +- T1: star topology, zephyr is the manifest repository +- T2: star topology, a Zephyr application is the manifest repository +- T3: forest topology, freestanding manifest repository + +T1: Star topology, zephyr is the manifest repository +==================================================== + +- The zephyr repository acts as the central repository and specifies + its :ref:`modules` in its :file:`west.yml` +- Analogy with existing mechanisms: Git submodules with zephyr as the + super-project + +This is the default. See :ref:`west-workspace` for how mainline Zephyr is an +example of this topology. + +.. _west-t2: + +T2: Star topology, application is the manifest repository +========================================================= + +- Useful for those focused on a single application +- A repository containing a Zephyr application acts as the central repository + and names other projects required to build it in its :file:`west.yml`. This + includes the zephyr repository and any modules. +- Analogy with existing mechanisms: Git submodules with the application as + the super-project, zephyr and other projects as submodules + +A workspace using this topology looks like this: + +.. code-block:: none + + west-workspace/ + │ + ├── application/ # .git/ │ + │   ├── CMakeLists.txt │ + │   ├── prj.conf │ never modified by west + │   ├── src/ │ + │   │   └── main.c │ + │   └── west.yml # main manifest with optional import(s) and override(s) + │ │ + ├── modules/ + │   └── lib/ + │   └── tinycbor/ # .git/ project from either the main manifest or some import. + │ + └── zephyr/ # .git/ project + └── west.yml # This can be partially imported with lower precedence or ignored. + # Only the 'manifest-rev' version can be imported. + + +Here is an example :file:`application/west.yml` which uses +:ref:`west-manifest-import`, available since west 0.7, to import Zephyr v2.2.0 +and its modules into the application manifest file: + +.. code-block:: yaml + + # Example T2 west.yml, using manifest imports. + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v2.2.0 + import: true + self: + path: application + +You can still selectively "override" individual Zephyr modules if you use +``import:`` in this way; see :ref:`west-manifest-ex1.3` for an example. + +Another way to do the same thing is to copy/paste :file:`zephyr/west.yml` +to :file:`application/west.yml`, adding an entry for the zephyr +project itself, like this: + +.. code-block:: yaml + + # Equivalent to the above, but with manually maintained Zephyr modules. + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + defaults: + remote: zephyrproject-rtos + projects: + - name: zephyr + revision: v2.2.0 + west-commands: scripts/west-commands.yml + - name: net-tools + revision: some-sha-goes-here + path: tools/net-tools + # ... other Zephyr modules go here ... + self: + path: application + +(The ``west-commands`` is there for :ref:`west-build-flash-debug` and other +Zephyr-specific :ref:`west-extensions`. It's not necessary when using +``import``.) + +The main advantage to using ``import`` is not having to track the revisions of +imported projects separately. In the above example, using ``import`` means +Zephyr's :ref:`module ` versions are automatically determined from the +:file:`zephyr/west.yml` revision, instead of having to be copy/pasted (and +maintained) on their own. + +T3: Forest topology +=================== + +- Useful for those supporting multiple independent applications or downstream + distributions with no "central" repository +- A dedicated manifest repository which contains no Zephyr source code, + and specifies a list of projects all at the same "level" +- Analogy with existing mechanisms: Google repo-based source distribution + +A workspace using this topology looks like this: + +.. code-block:: none + + west-workspace/ + ├── app1/ # .git/ project + │   ├── CMakeLists.txt + │   ├── prj.conf + │   └── src/ + │   └── main.c + ├── app2/ # .git/ project + │   ├── CMakeLists.txt + │   ├── prj.conf + │   └── src/ + │   └── main.c + ├── manifest-repo/ # .git/ never modified by west + │   └── west.yml # main manifest with optional import(s) and override(s) + ├── modules/ + │   └── lib/ + │   └── tinycbor/ # .git/ project from either the main manifest or + │ # from some import + │ + └── zephyr/ # .git/ project + └── west.yml # This can be partially imported with lower precedence or ignored. + # Only the 'manifest-rev' version can be imported. + +Here is an example T3 :file:`manifest-repo/west.yml` which uses +:ref:`west-manifest-import`, available since west 0.7, to import Zephyr +v2.2.0 and its modules, then add the ``app1`` and ``app2`` projects: + +.. code-block:: yaml + + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + - name: your-git-server + url-base: https://git.example.com/your-company + defaults: + remote: your-git-server + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v2.2.0 + import: true + - name: app1 + revision: SOME_SHA_OR_BRANCH_OR_TAG + - name: app2 + revision: ANOTHER_SHA_OR_BRANCH_OR_TAG + self: + path: manifest-repo + +You can also do this "by hand" by copy/pasting :file:`zephyr/west.yml` +as shown :ref:`above ` for the T2 topology, with the same caveats. From 570086da308a0dbd4721c246e82ae1a137dcdc0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Sat, 6 Feb 2021 13:30:51 -0800 Subject: [PATCH 096/226] doc: update west's workspaces.rst for 2.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We haven't updated the example revisions in the alternate topologies sections in a while. Update these for the upcoming 2.5 release. Signed-off-by: Martí Bolívar --- doc/guides/west/workspaces.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/guides/west/workspaces.rst b/doc/guides/west/workspaces.rst index bc485e7b..f581d5e4 100644 --- a/doc/guides/west/workspaces.rst +++ b/doc/guides/west/workspaces.rst @@ -189,7 +189,7 @@ A workspace using this topology looks like this: Here is an example :file:`application/west.yml` which uses -:ref:`west-manifest-import`, available since west 0.7, to import Zephyr v2.2.0 +:ref:`west-manifest-import`, available since west 0.7, to import Zephyr v2.5.0 and its modules into the application manifest file: .. code-block:: yaml @@ -202,7 +202,7 @@ and its modules into the application manifest file: projects: - name: zephyr remote: zephyrproject-rtos - revision: v2.2.0 + revision: v2.5.0 import: true self: path: application @@ -225,7 +225,7 @@ project itself, like this: remote: zephyrproject-rtos projects: - name: zephyr - revision: v2.2.0 + revision: v2.5.0 west-commands: scripts/west-commands.yml - name: net-tools revision: some-sha-goes-here @@ -281,7 +281,7 @@ A workspace using this topology looks like this: Here is an example T3 :file:`manifest-repo/west.yml` which uses :ref:`west-manifest-import`, available since west 0.7, to import Zephyr -v2.2.0 and its modules, then add the ``app1`` and ``app2`` projects: +v2.5.0 and its modules, then add the ``app1`` and ``app2`` projects: .. code-block:: yaml @@ -296,7 +296,7 @@ v2.2.0 and its modules, then add the ``app1`` and ``app2`` projects: projects: - name: zephyr remote: zephyrproject-rtos - revision: v2.2.0 + revision: v2.5.0 import: true - name: app1 revision: SOME_SHA_OR_BRANCH_OR_TAG From 672ad037de99b032d8c6ed6b111869aae7d0dd19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Sat, 6 Feb 2021 15:03:46 -0800 Subject: [PATCH 097/226] doc: add missing docs for 'west zephyr-export' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Something should have been added to zephyr-cmds.rst when this extension was added. Signed-off-by: Martí Bolívar --- doc/guides/west/zephyr-cmds.rst | 36 +++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/doc/guides/west/zephyr-cmds.rst b/doc/guides/west/zephyr-cmds.rst index 707fd12b..83a0849e 100644 --- a/doc/guides/west/zephyr-cmds.rst +++ b/doc/guides/west/zephyr-cmds.rst @@ -3,17 +3,7 @@ Additional Zephyr extension commands #################################### -Aside from the :ref:`build, flash, and debug commands `, -the zephyr tree extends the west command set with additional zephyr-specific -commands. - -.. Add a per-page contents at the top of the page. This page is nested - deeply enough that it doesn't have any subheadings in the main nav. - -.. only:: html - - .. contents:: - :local: +This page documents miscellaneous :ref:`west-zephyr-extensions`. .. _west-boards: @@ -36,3 +26,27 @@ flag:: Additional help about the formatting options can be found by running:: west boards -h + +.. _west-zephyr-export: + +Installing CMake packages: ``west zephyr-export`` +************************************************* + +This command registers the current Zephyr installation as a CMake +config package in the CMake user package registry. + +In Windows, the CMake user package registry is found in +``HKEY_CURRENT_USER\Software\Kitware\CMake\Packages``. + +In Linux and MacOS, the CMake user package registry is found in. +:file:`~/.cmake/packages`. + +You may run this command when setting up a Zephyr workspace. If you do, +application CMakeLists.txt files that are outside of your workspace will be +able to find the Zephyr repository with the following: + +.. code-block:: cmake + + find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +See :zephyr_file:`share/zephyr-package/cmake` for details. From 6a97b9b11fce84b2edbc0831c6ab5b7e767c64fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Sat, 6 Feb 2021 16:04:47 -0800 Subject: [PATCH 098/226] doc: improve manifest key docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create tables and Sphinx sections for the sub-keys of a manifest. List the subsections in the same order they are documented. This makes it easier to jump around in the document from the table of contents and see what's in each subkey. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 219 +++++++++++++++++++++++++---------- 1 file changed, 156 insertions(+), 63 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 250f76d5..6c7bbdeb 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -80,18 +80,18 @@ with some subsections, like this: .. code-block:: yaml manifest: - defaults: - # default project attributes (optional) remotes: # short names for project URLs (optional) projects: # a list of projects managed by west (mandatory) - group-filter: - # a list of project groups to enable or disable (optional) + defaults: + # default project attributes (optional) self: # configuration related to the manifest repository itself, # i.e. the repository containing west.yml (optional) version: # optional + group-filter: + # a list of project groups to enable or disable (optional) In YAML terms, the manifest file contains a mapping, with a ``manifest`` key. Any other keys and their contents are ignored (west v0.5 also required a @@ -102,7 +102,8 @@ The manifest contains subsections, like ``defaults``, ``remotes``, also a mapping, with these "subsections" as keys. Only ``projects`` is mandatory: this is the list of repositories managed by west and their metadata. -We'll cover the ``remotes`` and ``projects`` subsections in detail first. +Remotes +======= The ``remotes`` subsection contains a sequence which specifies the base URLs where projects can be fetched from. Each sequence element has a name and a "URL @@ -119,12 +120,31 @@ example: - name: remote2 url-base: https://git.example.com/base2 +The ``remotes`` keys and their usage are in the following table. + +.. list-table:: remotes keys + :header-rows: 1 + :widths: 1 5 + + * - Key + - Description + + * - ``name`` + - Mandatory; a unique name for the remote. + + * - ``url-base`` + - A prefix that is prepended to the fetch URL for each + project with this remote. + Above, two remotes are given, with names ``remote1`` and ``remote2``. Their URL bases are respectively ``https://git.example.com/base1`` and ``https://git.example.com/base2``. You can use SSH URL bases as well; for example, you might use ``git@example.com:base1`` if ``remote1`` supported Git over SSH as well. Anything acceptable to Git will work. +Projects +======== + The ``projects`` subsection contains a sequence describing the project repositories in the west workspace. Every project has a unique name. You can specify what Git remote URLs to use when cloning and fetching the projects, @@ -181,55 +201,87 @@ In this manifest: Its local path defaults to its name, ``proj3``. Commit ``abcde413a111`` will be checked out when it is next updated. -The list of project keys and their usage follows. Sometimes we'll refer to the -``defaults`` subsection; it will be described next. - -- ``name``: Mandatory. the name of the project. The name cannot be one of the - reserved values "west" or "manifest". The name must be unique in the manifest - file. -- ``remote`` or ``url``: Mandatory (one of the two, but not both). - - If the project has a ``remote``, that remote's ``url-base`` will be combined - with the project's ``name`` (or ``repo-path``, if it has one) to form the - fetch URL instead. - - If the project has a ``url``, that's the complete fetch URL for the - remote Git repository. - - If the project has neither, the ``defaults`` section must specify a - ``remote``, which will be used as the the project's remote. Otherwise, the - manifest is invalid. -- ``repo-path``: Optional. If given, this is concatenated on to the remote's - ``url-base`` instead of the project's ``name`` to form its fetch URL. - Projects may not have both ``url`` and ``repo-path`` attributes. -- ``revision``: Optional. The Git revision that ``west update`` should check - out. This will be checked out as a detached HEAD by default, to avoid - conflicting with local branch names. If not given, the ``revision`` value - from the ``defaults`` subsection will be used if present. - - A project revision can be a branch, tag, or SHA. The default ``revision`` is - ``master`` if not otherwise specified. -- ``path``: Optional. Relative path specifying where to clone the repository - locally, relative to the top directory in the west workspace. If missing, - the project's ``name`` is used as a directory name. -- ``clone-depth``: Optional. If given, a positive integer which creates a - shallow history in the cloned repository limited to the given number of - commits. This can only be used if the ``revision`` is a branch or tag. -- ``west-commands``: Optional. If given, a relative path to a YAML file within - the project which describes additional west commands provided by that - project. This file is named :file:`west-commands.yml` by convention. See - :ref:`west-extensions` for details. -- ``import``: Optional. If ``true``, imports projects from manifest files in - the given repository into the current manifest. See - :ref:`west-manifest-import` for details. -- ``groups``: Optional, a list of groups the project belongs to. See - :ref:`west-manifest-groups` for details. -- ``submodules``: Optional. You can use this to make ``west update`` also - update `Git submodules`_ defined by the project. See - :ref:`west-manifest-submodules` for details. +The available project keys and their usage are in the following table. +Sometimes we'll refer to the ``defaults`` subsection; it will be described +next. + +.. list-table:: projects elements keys + :header-rows: 1 + :widths: 1 5 + + * - Key(s) + - Description + + * - ``name`` + - Mandatory; a unique name for the project. The name cannot be one of the + reserved values "west" or "manifest". The name must be unique in the + manifest file. + + * - ``remote``, ``url`` + - Mandatory (one of the two, but not both). + + If the project has a ``remote``, that remote's ``url-base`` will be + combined with the project's ``name`` (or ``repo-path``, if it has one) + to form the fetch URL instead. + + If the project has a ``url``, that's the complete fetch URL for the + remote Git repository. + + If the project has neither, the ``defaults`` section must specify a + ``remote``, which will be used as the the project's remote. Otherwise, + the manifest is invalid. + + * - ``repo-path`` + - Optional. If given, this is concatenated on to the remote's + ``url-base`` instead of the project's ``name`` to form its fetch URL. + Projects may not have both ``url`` and ``repo-path`` attributes. + + * - ``revision`` + - Optional. The Git revision that ``west update`` should + check out. This will be checked out as a detached HEAD by default, to + avoid conflicting with local branch names. If not given, the + ``revision`` value from the ``defaults`` subsection will be used if + present. + + A project revision can be a branch, tag, or SHA. + + The default ``revision`` is ``master`` if not otherwise specified. + + * - ``path`` + - Optional. Relative path specifying where to clone the repository + locally, relative to the top directory in the west workspace. If missing, + the project's ``name`` is used as a directory name. + + * - ``clone-depth`` + - Optional. If given, a positive integer which creates a shallow history + in the cloned repository limited to the given number of commits. This + can only be used if the ``revision`` is a branch or tag. + + * - ``west-commands`` + - Optional. If given, a relative path to a YAML file within the project + which describes additional west commands provided by that project. This + file is named :file:`west-commands.yml` by convention. See + :ref:`west-extensions` for details. + + * - ``import`` + - Optional. If ``true``, imports projects from manifest files in the + given repository into the current manifest. See + :ref:`west-manifest-import` for details. + + * - ``groups`` + - Optional, a list of groups the project belongs to. See + :ref:`west-manifest-groups` for details. + + * - ``submodules`` + - Optional. You can use this to make ``west update`` also update `Git + submodules`_ defined by the project. See + :ref:`west-manifest-submodules` for details. .. _Git submodules: https://git-scm.com/book/en/v2/Git-Tools-Submodules +Defaults +======== + The ``defaults`` subsection can provide default values for project attributes. In particular, the default remote name and revision can be specified here. Another way to write the same manifest we have been describing @@ -259,21 +311,27 @@ so far using ``defaults`` is: url: https://github.com/user/project-three revision: abcde413a111 -The ``self`` subsection can be used to control the behavior of the -manifest repository itself. Its value is a map with the following keys: +The available ``defaults`` keys and their usage are in the following table. + +.. list-table:: defaults keys + :header-rows: 1 + :widths: 1 5 + + * - Key + - Description -- ``path``: Optional. The path to clone the manifest repository into, relative - to the west workspace's root directory. If not given, the basename of the - path component in the manifest repository URL will be used by default. For - example, if the URL is ``https://git.example.com/project-repo``, the manifest - repository would be cloned to the directory :file:`project-repo`. + * - ``remote`` + - Optional. This will be used for a project's ``remote`` if it does not + have a ``url`` or ``remote`` key set. -- ``west-commands``: Optional. This is analogous to the same key in a - project sequence element. + * - ``revision`` + - Optional. This will be used for a project's ``revision`` if it does + not have one set. If not given, the default is ``master``. -- ``import``: Optional. This is also analogous to the ``projects`` key, but - allows importing projects from other files in the manifest repository. See - :ref:`west-manifest-import`. +Self +==== + +The ``self`` subsection can be used to control the manifest repository itself. As an example, let's consider this snippet from the zephyr repository's :file:`west.yml`: @@ -293,8 +351,38 @@ zephyr repository does contain extension commands, its ``self`` entry declares the location of the corresponding :file:`west-commands.yml` relative to the repository root. +The available ``self`` keys and their usage are in the following table. + +.. list-table:: self keys + :header-rows: 1 + :widths: 1 5 + + * - Key + - Description + + * - ``path`` + - Optional. The path ``west init`` should clone the manifest repository + into, relative to the west workspace topdir. + + If not given, the basename of the path component in the manifest + repository URL will be used by default. For example, if the URL is + ``https://git.example.com/project-repo``, the manifest repository would + be cloned to the directory :file:`project-repo`. + + * - ``west-commands`` + - Optional. This is analogous to the same key in a project sequence + element. + + * - ``import`` + - Optional. This is also analogous to the ``projects`` key, but allows + importing projects from other files in the manifest repository. See + :ref:`west-manifest-import`. + .. _west-manifest-schema-version: +Version +======= + The ``version`` subsection can be used to mark the lowest version of the manifest file schema that can parse this file's data: @@ -316,6 +404,11 @@ manifest schema that cannot be parsed by west 0.7, then setting ``version: 21.0`` will cause west to print an error when attempting to parse the manifest data. +Group-filter +============ + +See :ref:`west-manifest-groups`. + .. _west-manifest-import: Manifest Imports From 630a7c84a727d8d4a8862939487a7d97885ae8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Sat, 6 Feb 2021 17:23:18 -0800 Subject: [PATCH 099/226] doc: improve docs on building without west MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it more obvious what needs to happen by spelling out the commands. Signed-off-by: Martí Bolívar --- doc/guides/west/without-west.rst | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/doc/guides/west/without-west.rst b/doc/guides/west/without-west.rst index 0f371c04..5a56aa20 100644 --- a/doc/guides/west/without-west.rst +++ b/doc/guides/west/without-west.rst @@ -46,17 +46,30 @@ As you pull changes in the zephyr repository, you will also need to maintain those additional repositories, adding new ones as necessary and keeping existing ones up to date at the latest revisions. -Specifying Modules ------------------- +Building applications +--------------------- + +You can build a Zephyr application using CMake and Ninja (or make) directly +without west installed if you specify any modules manually. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :tool: cmake + :goals: build + :gen-args: -DZEPHYR_MODULES=module1;module2;... + :compact: -If you have west installed, the Zephyr build system will use it to set -:ref:`ZEPHYR_MODULES `. If you don't have west -installed and your application does not need any of these -repositories, the build will still work. +When building with west installed, the Zephyr build system will use it to set +:ref:`ZEPHYR_MODULES `. + +If you don't have west installed and your application does not need any of +these repositories, the build will still work. If you don't have west installed and your application *does* need one of these repositories, you must set :makevar:`ZEPHYR_MODULES` -yourself. See :ref:`modules` for details. +yourself as shown above. + +See :ref:`modules` for more details. Flashing and Debugging ---------------------- From 4a0d2b01ae7746b43dd2dd26d85dcaa90bf2b23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 8 Feb 2021 07:11:37 -0800 Subject: [PATCH 100/226] doc: west: clean up example workspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Torsten Rasmussen Signed-off-by: Martí Bolívar --- doc/guides/west/basics.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/guides/west/basics.rst b/doc/guides/west/basics.rst index 132c707b..692eef75 100644 --- a/doc/guides/west/basics.rst +++ b/doc/guides/west/basics.rst @@ -20,9 +20,13 @@ workspace looks like this: zephyrproject/ # west topdir ├── .west/ # marks the location of the topdir │ └── config # per-workspace local configuration file - ├── zephyr/ # .git/ repo │ the manifest repository, - │ ├── west.yml # manifest file │ never modified by west - │ └── [... other files ...] │ after creation + │ + │ # The manifest repository, never modified by west after creation: + ├── zephyr/ # .git/ repo + │ ├── west.yml # manifest file + │ └── [... other files ...] + │ + │ # Projects managed by west: ├── modules/ │ └── lib/ │ └── tinycbor/ # .git/ project From 3214ab814152ae1252293690b2b5726e2ed3e118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 9 Feb 2021 16:28:50 -0800 Subject: [PATCH 101/226] doc: west: improve troubleshooting for west update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recommend curl -v or ssh -v. Suggested-by: Marc Herbert Signed-off-by: Martí Bolívar --- doc/guides/west/troubleshooting.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/guides/west/troubleshooting.rst b/doc/guides/west/troubleshooting.rst index e01000c6..7f016df2 100644 --- a/doc/guides/west/troubleshooting.rst +++ b/doc/guides/west/troubleshooting.rst @@ -27,9 +27,15 @@ something like this: west.manifest: running 'git fetch ... https://github.com/your-username/your_project ...' in /some/directory The ``git fetch`` command example in the last line above is what needs to -succeed. Go to ``/some/directory``, copy/paste and run the entire ``git fetch`` -command, then debug from there using the documentation for your credential -storage helper. +succeed. + +One strategy is to go to ``/some/directory``, copy/paste and run the entire +``git fetch`` command, then debug from there using the documentation for your +credential storage helper. + +If you're behind a corporate firewall and may have proxy or other issues, +``curl -v FETCH_URL`` (for HTTPS URLs) or ``ssh -v FETCH_URL`` (for SSH URLs) +may be helpful. If you can get the ``git fetch`` command to run successfully without prompting for a password when you run it directly, you will be able to run ``west From 9d3b0224992bf7aeff177793e00ecb8e68bdd3aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 22 Feb 2021 13:56:10 -0800 Subject: [PATCH 102/226] doc: west: make it clearer how to override the default runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Though BOARD_FLASH_RUNNER and BOARD_DEBUG_RUNNER are documented in the debug host tools page, these variables are important enough to deserve mention in the section dedicated to choosing a runner. Make it so. Signed-off-by: Martí Bolívar --- doc/guides/west/build-flash-debug.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 47bcd16c..079e5a5a 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -381,6 +381,19 @@ the default with:: west flash --runner jlink +You can override the default flash runner at build time by using the +``BOARD_FLASH_RUNNER`` CMake variable, and the debug runner with +``BOARD_DEBUG_RUNNER``. + +For example:: + + # Set the default runner to "jlink", overriding the board's + # usual default. + west build [...] -- -DBOARD_FLASH_RUNNER=jlink + +See :ref:`west-building-cmake-args` and :ref:`west-building-cmake-config` for +more information on setting CMake arguments. + See :ref:`west-runner` below for more information on the ``runner`` library used by West. The list of runners which support flashing can be obtained with ``west flash -H``; if run from a build directory or From ebd63352b2f37ddfb90439b2856a0440eb6494ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 16 Feb 2021 15:15:42 -0800 Subject: [PATCH 103/226] doc: west: move 'manifest imports' to bottom of manifest.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This diff is deceptively complicated. No text is being added or removed; the only thing that's being done is that the entire 'Manifest Imports' section is being moved down below the groups and submodules sections. This is prep work for a later commit which will document revised semantics for mixing 'import' with 'group-filter'. This will make 'group-filter' values compose across imports, so it will be useful to have documentation for group and group-filter before documentation for imports. That will let us document the way they work together within the 'Manifest Imports' section without using concepts that haven't yet been defined. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 1912 +++++++++++++++++----------------- 1 file changed, 956 insertions(+), 956 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 6c7bbdeb..b3acd0ba 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -409,1334 +409,1334 @@ Group-filter See :ref:`west-manifest-groups`. -.. _west-manifest-import: +.. _west-manifest-groups: -Manifest Imports -**************** +Project Groups and Active Projects +********************************** -You can use the ``import`` key briefly described above to include projects from -other manifest files in your :file:`west.yml`. This key can be either a -``project`` or ``self`` section attribute: +You can use the ``groups`` and ``group-filter`` keys briefly described +:ref:`above ` to place projects into groups, and filter +which groups are enabled. These keys appear in the manifest like this: .. code-block:: yaml manifest: projects: - name: some-project - import: ... - self: - import: ... + groups: ... + group-filter: ... -You can use a "self: import:" to load additional files from the repository -containing your :file:`west.yml`. You can use a "project: ... import:" to load -additional files defined in that project's Git history. +You can enable or disable project groups using ``group-filter``. Projects whose +groups are all disabled are *inactive*; west essentially ignores inactive +projects unless explicitly requested not to. -West resolves the final manifest from individual manifest files in this order: +The next section introduces project groups; the following sections describe +:ref:`west-enabled-disabled-groups` and :ref:`west-active-inactive-projects`. +Finally, there are :ref:`west-project-group-examples`. -#. imported files in ``self`` -#. your :file:`west.yml` file -#. imported files in ``projects`` +Project Groups +============== -During resolution, west ignores projects which have already been defined in -other files. For example, a project named ``foo`` in your :file:`west.yml` -makes west ignore other projects named ``foo`` imported from your ``projects`` -list. +Inside ``manifest: projects:``, you can add a project to one or more groups. +The ``groups`` key is a list of group names. Group names are strings. -The ``import`` key can be a boolean, path, mapping, or sequence. We'll describe -these in order, using examples: +For example, in this manifest fragment: -- :ref:`Boolean ` - - :ref:`west-manifest-ex1.1` - - :ref:`west-manifest-ex1.2` - - :ref:`west-manifest-ex1.3` -- :ref:`Relative path ` - - :ref:`west-manifest-ex2.1` - - :ref:`west-manifest-ex2.2` - - :ref:`west-manifest-ex2.3` -- :ref:`Mapping with additional configuration ` - - :ref:`west-manifest-ex3.1` - - :ref:`west-manifest-ex3.2` - - :ref:`west-manifest-ex3.3` - - :ref:`west-manifest-ex3.4` -- :ref:`Sequence of paths and mappings ` - - :ref:`west-manifest-ex4.1` - - :ref:`west-manifest-ex4.2` +.. code-block:: yaml -A more :ref:`formal description ` of how this works is -last, after the examples. + manifest: + projects: + - name: project-1 + groups: + - groupA + - name: project-2 + groups: + - groupB + - groupC + - name: project-3 -Troubleshooting Note -==================== +The projects are in these groups: -If you're using this feature and find west's behavior confusing, try -:ref:`resolving your manifest ` to see the final results -after imports are done. +- ``project-1``: one group, named ``groupA`` +- ``project-2``: two groups, named ``groupB`` and ``groupC`` +- ``project-3``: no groups -.. _west-manifest-import-bool: +Project group names must not contain commas (,), colons (:), or whitespace. -Option 1: Boolean -================= +Group names must not begin with a dash (-) or the plus sign (+), but they may +contain these characters elsewhere in their names. For example, ``foo-bar`` and +``foo+bar`` are valid groups, but ``-foobar`` and ``+foobar`` are not. -This is the easiest way to use ``import``. +Group names are otherwise arbitrary strings. Group names are case sensitive. -If ``import`` is ``true`` as a ``projects`` attribute, west imports projects -from the :file:`west.yml` file in that project's root directory. If it's -``false`` or missing, it has no effect. For example, this manifest would import -:file:`west.yml` from the ``p1`` git repository at revision ``v1.0``: +As a restriction, no project may use both ``import:`` and ``groups:``. (This +avoids some edge cases whose semantics are difficult to specify.) + +.. _west-enabled-disabled-groups: + +Enabled and Disabled Project Groups +=================================== + +You can enable or disable project groups in both your manifest file and +:ref:`west-config`. + +All groups are enabled by default. + +Within the manifest file, the top level ``manifest: group-filter:`` value can +be used to disable project groups. To disable a group, prefix its name with a +dash (-). For example, in this manifest fragment: .. code-block:: yaml manifest: - # ... - projects: - - name: p1 - revision: v1.0 - import: true # Import west.yml from p1's v1.0 git tag - - name: p2 - import: false # Nothing is imported from p2. - - name: p3 # Nothing is imported from p3 either. + group-filter: [-groupA,-groupB] -It's an error to set ``import`` to either ``true`` or ``false`` inside -``self``, like this: +The groups named ``groupA`` and ``groupB`` are disabled by this +``group-filter`` value. + +The ``group-filter`` list is an ordinary YAML list, so you could have also +written this fragment like this: .. code-block:: yaml manifest: - # ... - self: - import: true # Error + group-filter: + - -groupA + - -groupB -.. _west-manifest-ex1.1: +However, this syntax is harder to read and therefore discouraged. -Example 1.1: Downstream of a Zephyr release -------------------------------------------- +Although it's not an error to enable groups within ``manifest: group-filter:``, +like this: -You have a source code repository you want to use with Zephyr v1.14.1 LTS. You -want to maintain the whole thing using west. You don't want to modify any of -the mainline repositories. +.. code-block:: yaml -In other words, the west workspace you want looks like this: + manifest: + ... + group-filter: [+groupA] -.. code-block:: none +doing so is redundant since groups are enabled by default. - my-downstream/ - ├── .west/ # west directory - ├── zephyr/ # mainline zephyr repository - │ └── west.yml # the v1.14.1 version of this file is imported - ├── modules/ # modules from mainline zephyr - │   ├── hal/ - │   └── [...other directories..] - ├── [ ... other projects ...] # other mainline repositories - └── my-repo/ # your downstream repository - ├── west.yml # main manifest importing zephyr/west.yml v1.14.1 - └── [...other files..] +Only the **top level manifest file's** ``manifest: group-filter:`` value has +any effect. The ``manifest: group-filter:`` values in any +:ref:`imported manifests ` are ignored. -You can do this with the following :file:`my-repo/west.yml`: +In addition to the manifest file, you can control which groups are enabled and +disabled using the ``manifest.group-filter`` configuration option. This option +is a comma-separated list of groups to enable and/or disable. -.. code-block:: yaml +To enable a group, add its name to the list prefixed with ``+``. To disable a +group, add its name prefixed with ``-``. For example, setting +``manifest.group-filter`` to ``+groupA,-groupB`` enables ``groupA``, and +disables ``groupB``. - # my-repo/west.yml: - manifest: - remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos - projects: - - name: zephyr - remote: zephyrproject-rtos - revision: v1.14.1 - import: true +The value of the configuration option overrides any data in the manifest file. +You can think of this as if the ``manifest.group-filter`` configuration option +is appended to the ``manifest: group-filter:`` list from YAML, with "last entry +wins" semantics. -You can then create the workspace on your computer like this, assuming -``my-repo`` is hosted at ``https://git.example.com/my-repo``: +.. _west-active-inactive-projects: -.. code-block:: console +Active and Inactive Projects +============================ - west init -m https://git.example.com/my-repo my-downstream - cd my-downstream - west update +All projects are *active* by default. Projects with no groups are always +active. A project is *inactive* if all of its groups are disabled. This is the +only way to make a project inactive. -After ``west init``, :file:`my-downstream/my-repo` will be cloned. +Most west commands that operate on projects will ignore inactive projects by +default. For example, :ref:`west-update` when run without arguments will not +update inactive projects. As another example, running ``west list`` without +arguments will not print information for inactive projects. -After ``west update``, all of the projects defined in the ``zephyr`` -repository's :file:`west.yml` at revision ``v1.14.1`` will be cloned into -:file:`my-downstream` as well. +.. _west-project-group-examples: -You can add and commit any code to :file:`my-repo` you please at this point, -including your own Zephyr applications, drivers, etc. See :ref:`application`. +Project Group Examples +====================== -.. _west-manifest-ex1.2: +This section contains example situations involving project groups and active +projects. The examples use both ``manifest: group-filter:`` YAML lists and +``manifest.group-filter`` configuration lists, to show how they work together. -Example 1.2: "Rolling release" Zephyr downstream ------------------------------------------------- +Note that the ``defaults`` and ``remotes`` data in the following manifests +isn't relevant except to make the examples complete and self-contained. -This is similar to :ref:`west-manifest-ex1.1`, except we'll use ``revision: -master`` for the zephyr repository: +Example 1: no disabled groups +----------------------------- + +The entire manifest file is: .. code-block:: yaml - # my-repo/west.yml: manifest: - remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos projects: - - name: zephyr - remote: zephyrproject-rtos - revision: master - import: true + - name: foo + groups: + - groupA + - name: bar + groups: + - groupA + - groupB + - name: baz -You can create the workspace in the same way: + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com -.. code-block:: console +The ``manifest.group-filter`` configuration option is not set (you can ensure +this by running ``west config -D manifest.group-filter``). - west init -m https://git.example.com/my-repo my-downstream - cd my-downstream - west update +No groups are disabled, because all groups are enabled by default. Therefore, +all three projects (``foo``, ``bar``, and ``baz``) are active. Note that there +is no way to make project ``baz`` inactive, since it has no groups. -This time, whenever you run ``west update``, the special :ref:`manifest-rev -` branch in the ``zephyr`` repository will be updated to -point at a newly fetched ``master`` branch tip from the URL -https://github.com/zephyrproject-rtos/zephyr. +Example 2: Disabling one group via manifest +------------------------------------------- -The contents of :file:`zephyr/west.yml` at the new ``manifest-rev`` will then -be used to import projects from Zephyr. This lets you stay up to date with the -latest changes in the Zephyr project. The cost is that running ``west update`` -will not produce reproducible results, since the remote ``master`` branch can -change every time you run it. +The entire manifest file is: -It's also important to understand that west **ignores your working tree's** -:file:`zephyr/west.yml` entirely when resolving imports. West always uses the -contents of imported manifests as they were committed to the latest -``manifest-rev`` when importing from a project. +.. code-block:: yaml -You can only import manifest from the file system if they are in your manifest -repository's working tree. See :ref:`west-manifest-ex2.2` for an example. + manifest: + projects: + - name: foo + groups: + - groupA + - name: bar + groups: + - groupA + - groupB -.. _west-manifest-ex1.3: + group-filter: [-groupA] -Example 1.3: Downstream of a Zephyr release, with module fork -------------------------------------------------------------- + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com -This manifest is similar to the one in :ref:`west-manifest-ex1.1`, except it: +The ``manifest.group-filter`` configuration option is not set (you can ensure +this by running ``west config -D manifest.group-filter``). -- is a downstream of Zephyr 2.0 -- includes a downstream fork of the :file:`modules/hal/nordic` - :ref:`module ` which was included in that release +Since ``groupA`` is disabled, project ``foo`` is inactive. Project ``bar`` is +active, because ``groupB`` is enabled. + +Example 3: Disabling multiple groups via manifest +------------------------------------------------- + +The entire manifest file is: .. code-block:: yaml - # my-repo/west.yml: manifest: - remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos - - name: my-remote - url-base: https://git.example.com projects: - - name: hal_nordic # higher precedence - remote: my-remote - revision: my-sha - path: modules/hal/nordic - - name: zephyr - remote: zephyrproject-rtos - revision: v2.0.0 - import: true # imported projects have lower precedence + - name: foo + groups: + - groupA + - name: bar + groups: + - groupA + - groupB + + group-filter: [-groupA,-groupB] - # subset of zephyr/west.yml contents at v2.0.0: - manifest: defaults: - remote: zephyrproject-rtos + remote: example-remote remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos - projects: - # ... - - name: hal_nordic # lower precedence, values ignored - path: modules/hal/nordic - revision: another-sha + - name: example-remote + url-base: https://git.example.com -With this manifest file, the project named ``hal_nordic``: +The ``manifest.group-filter`` configuration option is not set (you can ensure +this by running ``west config -D manifest.group-filter``). -- is cloned from ``https://git.example.com/hal_nordic`` instead of - ``https://github.com/zephyrproject-rtos/hal_nordic``. -- is updated to commit ``my-sha`` by ``west update``, instead of - the mainline commit ``another-sha`` +Both ``foo`` and ``bar`` are inactive, because all of their groups are +disabled. -In other words, when your top-level manifest defines a project, like -``hal_nordic``, west will ignore any other definition it finds later on while -resolving imports. +Example 4: Disabling a group via configuration +---------------------------------------------- -This does mean you have to copy the ``path: modules/hal/nordic`` value into -:file:`my-repo/west.yml` when defining ``hal_nordic`` there. The value from -:file:`zephyr/west.yml` is ignored entirely. See :ref:`west-manifest-resolve` -for troubleshooting advice if this gets confusing in practice. +The entire manifest file is: -When you run ``west update``, west will: +.. code-block:: yaml -- update zephyr's ``manifest-rev`` to point at the ``v2.0.0`` tag -- import :file:`zephyr/west.yml` at that ``manifest-rev`` -- locally check out the ``v2.0.0`` revisions for all zephyr projects except - ``hal_nordic`` -- update ``hal_nordic`` to ``my-sha`` instead of ``another-sha`` + manifest: + projects: + - name: foo + groups: + - groupA + - name: bar + groups: + - groupA + - groupB -.. _west-manifest-import-path: + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com -Option 2: Relative path -======================= +The ``manifest.group-filter`` configuration option is set to ``-groupA`` (you +can ensure this by running ``west config manifest.group-filter -- -groupA``; +the extra ``--`` is required so the argument parser does not treat ``-groupA`` +as a command line option ``-g`` with value ``roupA``). -The ``import`` value can also be a relative path to a manifest file or a -directory containing manifest files. The path is relative to the root directory -of the ``projects`` or ``self`` repository the ``import`` key appears in. +Project ``foo`` is inactive because ``groupA`` has been disabled by the +``manifest.group-filter`` configuration option. Project ``bar`` is active +because ``groupB`` is enabled. -Here is an example: +Example 5: Overriding a disabled group via configuration +-------------------------------------------------------- + +The entire manifest file is: .. code-block:: yaml manifest: projects: - - name: project-1 - revision: v1.0 - import: west.yml - - name: project-2 - revision: master - import: p2-manifests - self: - import: submanifests + - name: foo + - name: bar + groups: + - groupA + - name: baz + groups: + - groupA + - groupB -This will import the following: + group-filter: [-groupA] -- the contents of :file:`project-1/west.yml` at ``manifest-rev``, which points - at tag ``v1.0`` after running ``west update`` -- any YAML files in the directory tree :file:`project-2/p2-manifests` - at the latest ``master``, as fetched by ``west update``, sorted by file name -- YAML files in :file:`submanifests` in your manifest repository, - as they appear on your file system, sorted by file name + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com -Notice how ``projects`` imports get data from Git using ``manifest-rev``, while -``self`` imports get data from your file system. This is because as usual, west -leaves version control for your manifest repository up to you. +The ``manifest.group-filter`` configuration option is set to ``+groupA`` (you +can ensure this by running ``west config manifest.group-filter +groupA``). -.. _west-manifest-ex2.1: +In this case, ``groupA`` is enabled: the ``manifest.group-filter`` +configuration option has higher precedence than the ``manifest: group-filter: +[-groupA]`` content in the manifest file. -Example 2.1: Downstream of a Zephyr release with explicit path --------------------------------------------------------------- +Therefore, projects ``foo`` and ``bar`` are both active. -This is an explicit way to write an equivalent manifest to the one in -:ref:`west-manifest-ex1.1`. +Example 6: Overriding multiple disabled groups via configuration +---------------------------------------------------------------- + +The entire manifest file is: .. code-block:: yaml manifest: - remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos projects: - - name: zephyr - remote: zephyrproject-rtos - revision: v1.14.1 - import: west.yml - -The setting ``import: west.yml`` means to use the file :file:`west.yml` inside -the ``zephyr`` project. This example is contrived, but shows the idea. - -This can be useful in practice when the name of the manifest file you want to -import is not :file:`west.yml`. + - name: foo + - name: bar + groups: + - groupA + - name: baz + groups: + - groupA + - groupB -.. _west-manifest-ex2.2: + group-filter: [-groupA,-groupB] -Example 2.2: Downstream with directory of manifest files --------------------------------------------------------- + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com -Your Zephyr downstream has a lot of additional repositories. So many, in fact, -that you want to split them up into multiple manifest files, but keep track of -them all in a single manifest repository, like this: +The ``manifest.group-filter`` configuration option is set to +``+groupA,+groupB`` (you can ensure this by running ``west config +manifest.group-filter "+groupA,+groupB"``). -.. code-block:: none +In this case, both ``groupA`` and ``groupB`` are enabled, because the +configuration value overrides the manifest file for both groups. - my-repo/ - ├── submanifests - │ ├── 01-libraries.yml - │ ├── 02-vendor-hals.yml - │ └── 03-applications.yml - └── west.yml +Therefore, projects ``foo`` and ``bar`` are both active. -You want to add all the files in :file:`my-repo/submanifests` to the main -manifest file, :file:`my-repo/west.yml`, in addition to projects in -:file:`zephyr/west.yml`. You want to track the latest mainline master -instead of using a fixed revision. +Example 7: Disabling multiple groups via configuration +------------------------------------------------------ -Here's how: +The entire manifest file is: .. code-block:: yaml - # my-repo/west.yml: manifest: - remotes: - - name: zephyrproject-rtos - url-base: https://github.com/zephyrproject-rtos projects: - - name: zephyr - remote: zephyrproject-rtos - import: true - self: - import: submanifests - -Manifest files are imported in this order during resolution: - -#. :file:`my-repo/submanifests/01-libraries.yml` -#. :file:`my-repo/submanifests/02-vendor-hals.yml` -#. :file:`my-repo/submanifests/03-applications.yml` -#. :file:`my-repo/west.yml` -#. :file:`zephyr/west.yml` - -.. note:: - - The :file:`.yml` file names are prefixed with numbers in this example to - make sure they are imported in the specified order. - - You can pick arbitrary names. West sorts files in a directory by name before - importing. + - name: foo + - name: bar + groups: + - groupA + - name: baz + groups: + - groupA + - groupB -Notice how the manifests in :file:`submanifests` are imported *before* -:file:`my-repo/west.yml` and :file:`zephyr/west.yml`. In general, an ``import`` -in the ``self`` section is processed before the manifest files in ``projects`` -and the main manifest file. + defaults: + remote: example-remote + remotes: + - name: example-remote + url-base: https://git.example.com -This means projects defined in :file:`my-repo/submanifests` take highest -precedence. For example, if :file:`01-libraries.yml` defines ``hal_nordic``, -the project by the same name in :file:`zephyr/west.yml` is simply ignored. As -usual, see :ref:`west-manifest-resolve` for troubleshooting advice. +The ``manifest.group-filter`` configuration option is set to +``-groupA,-groupB`` (you can ensure this by running ``west config +manifest.group-filter -- "-groupA,-groupB"``). -This may seem strange, but it allows you to redefine projects "after the fact", -as we'll see in the next example. +In this case, both ``groupA`` and ``groupB`` are disabled. -.. _west-manifest-ex2.3: +Therefore, projects ``foo`` and ``bar`` are both inactive. -Example 2.3: Continuous Integration overrides ---------------------------------------------- +.. _west-manifest-submodules: -Your continuous integration system needs to fetch and test multiple -repositories in your west workspace from a developer's forks instead of your -mainline development trees, to see if the changes all work well together. +Git Submodules in Projects +************************** -Starting with :ref:`west-manifest-ex2.2`, the CI scripts add a -file :file:`00-ci.yml` in :file:`my-repo/submanifests`, with these contents: +You can use the ``submodules`` keys briefly described :ref:`above +` to force ``west update`` to also handle any `Git +submodules`_ configured in project's git repository. The ``submodules`` key can +appear inside ``projects``, like this: -.. code-block:: yaml +.. code-block:: YAML - # my-repo/submanifests/00-ci.yml: manifest: projects: - - name: a-vendor-hal - url: https://github.com/a-developer/hal - revision: a-pull-request-branch - - name: an-application - url: https://github.com/a-developer/application - revision: another-pull-request-branch - -The CI scripts run ``west update`` after generating this file in -:file:`my-repo/submanifests`. The projects defined in :file:`00-ci.yml` have -higher precedence than other definitions in :file:`my-repo/submanifests`, -because the name :file:`00-ci.yml` comes before the other file names. - -Thus, ``west update`` always checks out the developer's branches in the -projects named ``a-vendor-hal`` and ``an-application``, even if those same -projects are also defined elsewhere. + - name: some-project + submodules: ... -.. _west-manifest-import-map: +The ``submodules`` key can be a boolean or a list of mappings. We'll describe +these in order. -Option 3: Mapping +Option 1: Boolean ================= -The ``import`` key can also contain a mapping with the following keys: - -- ``file``: Optional. The name of the manifest file or directory to import. - This defaults to :file:`west.yml` if not present. -- ``name-allowlist``: Optional. If present, a name or sequence of project names - to include. -- ``path-allowlist``: Optional. If present, a path or sequence of project paths - to match against. This is a shell-style globbing pattern, currently - implemented with `pathlib`_. Note that this means case sensitivity is - platform specific. -- ``name-blocklist``: Optional. Like ``name-allowlist``, but contains project - names to exclude rather than include. -- ``path-blocklist``: Optional. Like ``path-allowlist``, but contains project - paths to exclude rather than include. -- ``path-prefix``: Optional (new in v0.8.0). If given, this will be prepended - to the project's path in the workspace, as well as the paths of any imported - projects. This can be used to place these projects in a subdirectory of the - workspace. - -.. _re: https://docs.python.org/3/library/re.html -.. _pathlib: - https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.match - -Allowlists override blocklists if both are given. For example, if a project is -blocked by path, then allowed by name, it will still be imported. +This is the easiest way to use ``submodules``. -.. _west-manifest-ex3.1: +If ``submodules`` is ``true`` as a ``projects`` attribute, ``west update`` will +recursively update the project's Git submodules whenever it updates the project +itself. If it's ``false`` or missing, it has no effect. -Example 3.1: Downstream with name allowlist -------------------------------------------- +For example, let's say you have a source code repository ``foo``, which has +some submodules, and you want ``west update`` to keep all of them them in sync, +along with another project named ``bar`` in the same workspace. -Here is a pair of manifest files, representing a mainline and a -downstream. The downstream doesn't want to use all the mainline -projects, however. We'll assume the mainline :file:`west.yml` is -hosted at ``https://git.example.com/mainline/manifest``. +You can do that with this manifest file: .. code-block:: yaml - # mainline west.yml: manifest: projects: - - name: mainline-app # included - path: examples/app - url: https://git.example.com/mainline/app - - name: lib - path: libraries/lib - url: https://git.example.com/mainline/lib - - name: lib2 # included - path: libraries/lib2 - url: https://git.example.com/mainline/lib2 + - name: foo + submodules: true + - name: bar - # downstream west.yml: - manifest: - projects: - - name: mainline - url: https://git.example.com/mainline/manifest - import: - name-allowlist: - - mainline-app - - lib2 - - name: downstream-app - url: https://git.example.com/downstream/app - - name: lib3 - path: libraries/lib3 - url: https://git.example.com/downstream/lib3 +Here, ``west update`` will initialize and update all submodules in ``foo``. If +``bar`` has any submodules, they are ignored, because ``bar`` does not have a +``submodules`` value. -An equivalent manifest in a single file would be: +Option 2: List of mappings +========================== + +The ``submodules`` key may be a list of mappings. Each element in the list +defines the name of the submodule to update, and the path -- relative to the +project's absolute path in the workspace -- to use for the submodule. +The submodule will be updated recursively. + +For example, let's say you have a source code repository ``foo``, which has +many submodules, and you want ``west update`` to keep some but not all of them +in sync, along with another project named ``bar`` in the same workspace. + +You can do that with this manifest file: .. code-block:: yaml manifest: projects: - - name: mainline - url: https://git.example.com/mainline/manifest - - name: downstream-app - url: https://git.example.com/downstream/app - - name: lib3 - path: libraries/lib3 - url: https://git.example.com/downstream/lib3 - - name: mainline-app # imported - path: examples/app - url: https://git.example.com/mainline/app - - name: lib2 # imported - path: libraries/lib2 - url: https://git.example.com/mainline/lib2 + - name: foo + submodules: + - name: foo-first-sub + path: path/to/foo-first-sub + - name: foo-second-sub + path: path/to/foo-second-sub + - name: bar -If an allowlist had not been used, the ``lib`` project from the mainline -manifest would have been imported. +Here, ``west update`` will recursively initialize and update just the +submodules in ``foo`` with paths ``path/to/foo-first-sub`` and +``path/to/foo-second-sub``. Any submodules in ``bar`` are still ignored. -.. _west-manifest-ex3.2: +.. _west-manifest-import: -Example 3.2: Downstream with path allowlist -------------------------------------------- +Manifest Imports +**************** -Here is an example showing how to allowlist mainline's libraries only, -using ``path-allowlist``. +You can use the ``import`` key briefly described above to include projects from +other manifest files in your :file:`west.yml`. This key can be either a +``project`` or ``self`` section attribute: .. code-block:: yaml - # mainline west.yml: manifest: projects: - - name: app - path: examples/app - url: https://git.example.com/mainline/app - - name: lib - path: libraries/lib # included - url: https://git.example.com/mainline/lib - - name: lib2 - path: libraries/lib2 # included - url: https://git.example.com/mainline/lib2 + - name: some-project + import: ... + self: + import: ... - # downstream west.yml: - manifest: - projects: - - name: mainline - url: https://git.example.com/mainline/manifest - import: - path-allowlist: libraries/* - - name: app - url: https://git.example.com/downstream/app - - name: lib3 - path: libraries/lib3 - url: https://git.example.com/downstream/lib3 +You can use a "self: import:" to load additional files from the repository +containing your :file:`west.yml`. You can use a "project: ... import:" to load +additional files defined in that project's Git history. -An equivalent manifest in a single file would be: +West resolves the final manifest from individual manifest files in this order: -.. code-block:: yaml +#. imported files in ``self`` +#. your :file:`west.yml` file +#. imported files in ``projects`` - manifest: - projects: - - name: lib # imported - path: libraries/lib - url: https://git.example.com/mainline/lib - - name: lib2 # imported - path: libraries/lib2 - url: https://git.example.com/mainline/lib2 - - name: mainline - url: https://git.example.com/mainline/manifest - - name: app - url: https://git.example.com/downstream/app - - name: lib3 - path: libraries/lib3 - url: https://git.example.com/downstream/lib3 +During resolution, west ignores projects which have already been defined in +other files. For example, a project named ``foo`` in your :file:`west.yml` +makes west ignore other projects named ``foo`` imported from your ``projects`` +list. -.. _west-manifest-ex3.3: +The ``import`` key can be a boolean, path, mapping, or sequence. We'll describe +these in order, using examples: -Example 3.3: Downstream with path blocklist -------------------------------------------- +- :ref:`Boolean ` + - :ref:`west-manifest-ex1.1` + - :ref:`west-manifest-ex1.2` + - :ref:`west-manifest-ex1.3` +- :ref:`Relative path ` + - :ref:`west-manifest-ex2.1` + - :ref:`west-manifest-ex2.2` + - :ref:`west-manifest-ex2.3` +- :ref:`Mapping with additional configuration ` + - :ref:`west-manifest-ex3.1` + - :ref:`west-manifest-ex3.2` + - :ref:`west-manifest-ex3.3` + - :ref:`west-manifest-ex3.4` +- :ref:`Sequence of paths and mappings ` + - :ref:`west-manifest-ex4.1` + - :ref:`west-manifest-ex4.2` -Here's an example showing how to block all vendor HALs from mainline by -common path prefix in the workspace, add your own version for the chip -you're targeting, and keep everything else. +A more :ref:`formal description ` of how this works is +last, after the examples. -.. code-block:: yaml +Troubleshooting Note +==================== - # mainline west.yml: - manifest: - defaults: - remote: mainline - remotes: - - name: mainline - url-base: https://git.example.com/mainline - projects: - - name: app - - name: lib - path: libraries/lib - - name: lib2 - path: libraries/lib2 - - name: hal_foo - path: modules/hals/foo # excluded - - name: hal_bar - path: modules/hals/bar # excluded - - name: hal_baz - path: modules/hals/baz # excluded +If you're using this feature and find west's behavior confusing, try +:ref:`resolving your manifest ` to see the final results +after imports are done. - # downstream west.yml: - manifest: - projects: - - name: mainline - url: https://git.example.com/mainline/manifest - import: - path-blocklist: modules/hals/* - - name: hal_foo - path: modules/hals/foo - url: https://git.example.com/downstream/hal_foo +.. _west-manifest-import-bool: -An equivalent manifest in a single file would be: +Option 1: Boolean +================= + +This is the easiest way to use ``import``. + +If ``import`` is ``true`` as a ``projects`` attribute, west imports projects +from the :file:`west.yml` file in that project's root directory. If it's +``false`` or missing, it has no effect. For example, this manifest would import +:file:`west.yml` from the ``p1`` git repository at revision ``v1.0``: .. code-block:: yaml manifest: - defaults: - remote: mainline - remotes: - - name: mainline - url-base: https://git.example.com/mainline + # ... projects: - - name: app # imported - - name: lib # imported - path: libraries/lib - - name: lib2 # imported - path: libraries/lib2 - - name: mainline - repo-path: https://git.example.com/mainline/manifest - - name: hal_foo - path: modules/hals/foo - url: https://git.example.com/downstream/hal_foo + - name: p1 + revision: v1.0 + import: true # Import west.yml from p1's v1.0 git tag + - name: p2 + import: false # Nothing is imported from p2. + - name: p3 # Nothing is imported from p3 either. -.. _west-manifest-ex3.4: +It's an error to set ``import`` to either ``true`` or ``false`` inside +``self``, like this: -Example 3.4: Import into a subdirectory ---------------------------------------- +.. code-block:: yaml -You want to import a manifest and its projects, placing everything into a -subdirectory of your :term:`west workspace`. + manifest: + # ... + self: + import: true # Error -For example, suppose you want to import this manifest from project ``foo``, -adding this project and its projects ``bar`` and ``baz`` to your workspace: +.. _west-manifest-ex1.1: -.. code-block:: yaml +Example 1.1: Downstream of a Zephyr release +------------------------------------------- - # foo/west.yml: - manifest: - defaults: - remote: example - remotes: - - name: example - url-base: https://git.example.com - projects: - - name: bar - - name: baz +You have a source code repository you want to use with Zephyr v1.14.1 LTS. You +want to maintain the whole thing using west. You don't want to modify any of +the mainline repositories. -Instead of importing these into the top level workspace, you want to place all -three project repositories in an :file:`external-code` subdirectory, like this: +In other words, the west workspace you want looks like this: .. code-block:: none - workspace/ - └── external-code/ - ├── foo/ - ├── bar/ - └── baz/ + my-downstream/ + ├── .west/ # west directory + ├── zephyr/ # mainline zephyr repository + │ └── west.yml # the v1.14.1 version of this file is imported + ├── modules/ # modules from mainline zephyr + │   ├── hal/ + │   └── [...other directories..] + ├── [ ... other projects ...] # other mainline repositories + └── my-repo/ # your downstream repository + ├── west.yml # main manifest importing zephyr/west.yml v1.14.1 + └── [...other files..] -You can do this using this manifest: +You can do this with the following :file:`my-repo/west.yml`: .. code-block:: yaml + # my-repo/west.yml: manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos projects: - - name: foo - url: https://git.example.com/foo - import: - path-prefix: external-code + - name: zephyr + remote: zephyrproject-rtos + revision: v1.14.1 + import: true -An equivalent manifest in a single file would be: +You can then create the workspace on your computer like this, assuming +``my-repo`` is hosted at ``https://git.example.com/my-repo``: -.. code-block:: yaml +.. code-block:: console - # foo/west.yml: - manifest: - defaults: - remote: example - remotes: - - name: example - url-base: https://git.example.com - projects: - - name: foo - path: external-code/foo - - name: bar - path: external-code/bar - - name: baz - path: external-code/baz + west init -m https://git.example.com/my-repo my-downstream + cd my-downstream + west update -.. _west-manifest-import-seq: +After ``west init``, :file:`my-downstream/my-repo` will be cloned. -Option 4: Sequence -================== +After ``west update``, all of the projects defined in the ``zephyr`` +repository's :file:`west.yml` at revision ``v1.14.1`` will be cloned into +:file:`my-downstream` as well. -The ``import`` key can also contain a sequence of files, directories, -and mappings. +You can add and commit any code to :file:`my-repo` you please at this point, +including your own Zephyr applications, drivers, etc. See :ref:`application`. -.. _west-manifest-ex4.1: +.. _west-manifest-ex1.2: -Example 4.1: Downstream with sequence of manifest files -------------------------------------------------------- +Example 1.2: "Rolling release" Zephyr downstream +------------------------------------------------ -This example manifest is equivalent to the manifest in -:ref:`west-manifest-ex2.2`, with a sequence of explicitly named files. +This is similar to :ref:`west-manifest-ex1.1`, except we'll use ``revision: +master`` for the zephyr repository: .. code-block:: yaml # my-repo/west.yml: manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos projects: - name: zephyr - url: https://github.com/zephyrproject-rtos/zephyr - import: west.yml - self: - import: - - submanifests/01-libraries.yml - - submanifests/02-vendor-hals.yml - - submanifests/03-applications.yml - -.. _west-manifest-ex4.2: + remote: zephyrproject-rtos + revision: master + import: true -Example 4.2: Import order illustration --------------------------------------- +You can create the workspace in the same way: -This more complicated example shows the order that west imports manifest files: +.. code-block:: console -.. code-block:: yaml + west init -m https://git.example.com/my-repo my-downstream + cd my-downstream + west update - # my-repo/west.yml - manifest: - # ... - projects: - - name: my-library - - name: my-app - - name: zephyr - import: true - - name: another-manifest-repo - import: submanifests - self: - import: - - submanifests/libraries.yml - - submanifests/vendor-hals.yml - - submanifests/applications.yml - defaults: - remote: my-remote +This time, whenever you run ``west update``, the special :ref:`manifest-rev +` branch in the ``zephyr`` repository will be updated to +point at a newly fetched ``master`` branch tip from the URL +https://github.com/zephyrproject-rtos/zephyr. -For this example, west resolves imports in this order: +The contents of :file:`zephyr/west.yml` at the new ``manifest-rev`` will then +be used to import projects from Zephyr. This lets you stay up to date with the +latest changes in the Zephyr project. The cost is that running ``west update`` +will not produce reproducible results, since the remote ``master`` branch can +change every time you run it. -#. the listed files in :file:`my-repo/submanifests` are first, in the order - they occur (e.g. :file:`libraries.yml` comes before - :file:`applications.yml`, since this is a sequence of files), since the - ``self: import:`` is always imported first -#. :file:`my-repo/west.yml` is next (with projects ``my-library`` etc. as long - as they weren't already defined somewhere in :file:`submanifests`) -#. :file:`zephyr/west.yml` is after that, since that's the first ``import`` key - in the ``projects`` list in :file:`my-repo/west.yml` -#. files in :file:`another-manifest-repo/submanifests` are last (sorted by file - name), since that's the final project ``import`` +It's also important to understand that west **ignores your working tree's** +:file:`zephyr/west.yml` entirely when resolving imports. West always uses the +contents of imported manifests as they were committed to the latest +``manifest-rev`` when importing from a project. -.. _west-manifest-formal: +You can only import manifest from the file system if they are in your manifest +repository's working tree. See :ref:`west-manifest-ex2.2` for an example. -Manifest Import Details -======================= +.. _west-manifest-ex1.3: -This section describes how west imports a manifest file a bit more formally. +Example 1.3: Downstream of a Zephyr release, with module fork +------------------------------------------------------------- -Overview --------- +This manifest is similar to the one in :ref:`west-manifest-ex1.1`, except it: -A west manifest's ``projects`` and ``self`` sections can have ``import`` keys, -like so: +- is a downstream of Zephyr 2.0 +- includes a downstream fork of the :file:`modules/hal/nordic` + :ref:`module ` which was included in that release .. code-block:: yaml - # Top-level west.yml. + # my-repo/west.yml: manifest: - # ... + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + - name: my-remote + url-base: https://git.example.com projects: - - name: foo - revision: rev-1 - import: import-1 - - name: bar - revision: rev-2 - import: import-2 - # ... - - name: baz - revision: rev-N - import: import-N - self: - import: self-import - -Import keys are optional. If any of ``import-1, ..., import-N`` are missing, -west will not import additional manifest data from that project. If -``self-import`` is missing, no additional files in the manifest repository -(beyond the top-level west.yml) are imported. - -The ultimate outcome of resolving manifest imports is a final list of projects, -which is produced by combining the ``projects`` defined in the top-level file -with those defined in imported files. Importing is done in this order: - -#. Manifests from ``self-import`` are imported first. -#. The top-level manifest file's ``projects`` are added in next. -#. Manifests from ``import-1``, ..., ``import-N``, are imported in that order. + - name: hal_nordic # higher precedence + remote: my-remote + revision: my-sha + path: modules/hal/nordic + - name: zephyr + remote: zephyrproject-rtos + revision: v2.0.0 + import: true # imported projects have lower precedence -This process recurses if necessary. + # subset of zephyr/west.yml contents at v2.0.0: + manifest: + defaults: + remote: zephyrproject-rtos + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + # ... + - name: hal_nordic # lower precedence, values ignored + path: modules/hal/nordic + revision: another-sha -Projects are identified by name. If the same name occurs in multiple manifests, -the first definition is used, and subsequent definitions are ignored. For -example, if ``import-1`` contains a project named ``bar``, that is ignored, -because the top-level :file:`west.yml` has already defined a project by that -name. +With this manifest file, the project named ``hal_nordic``: -The contents of files named by ``import-1`` through ``import-N`` are imported -from Git at the latest ``manifest-rev`` revisions in their projects. These -revisions can be updated to the values ``rev-1`` through ``rev-N`` by running -``west update``. If any ``manifest-rev`` reference is missing or out of date, -``west update`` also fetches project data from the remote fetch URL and updates -the reference. +- is cloned from ``https://git.example.com/hal_nordic`` instead of + ``https://github.com/zephyrproject-rtos/hal_nordic``. +- is updated to commit ``my-sha`` by ``west update``, instead of + the mainline commit ``another-sha`` -Also note that all imported manifests, from the root manifest to the repository -which defines a project ``P``, must be up to date in order for west to update -``P`` itself. For example, this means ``west update P`` would update -``manifest-rev`` in the ``baz`` project if :file:`baz/west.yml` defines ``P``, -as well as updating the ``manifest-rev`` branch in the local git clone of -``P``. Confusingly, the update of ``baz`` may result in the removal of ``P`` -from :file:`baz/west.yml`, which would cause ``west update P`` to fail with an -unrecognized project! +In other words, when your top-level manifest defines a project, like +``hal_nordic``, west will ignore any other definition it finds later on while +resolving imports. -For this reason, it's usually best to run plain ``west update`` to avoid errors -if you use manifest imports. By default, west won't fetch any project data over -the network if a project's revision is a SHA or tag which is already available -locally, so updating the extra projects shouldn't take too much time unless -it's really needed. See the documentation for the :ref:`update.fetch -` configuration option for more information. +This does mean you have to copy the ``path: modules/hal/nordic`` value into +:file:`my-repo/west.yml` when defining ``hal_nordic`` there. The value from +:file:`zephyr/west.yml` is ignored entirely. See :ref:`west-manifest-resolve` +for troubleshooting advice if this gets confusing in practice. -If an imported manifest file has a ``west-commands:`` definition in its -``self:`` section, the extension commands defined there are added to the set of -available extensions at the time the manifest is imported. They will thus take -precedence over any extension commands with the same names added later on. +When you run ``west update``, west will: -When an individual ``import`` key refers to multiple manifest files, they are -processed in this order: +- update zephyr's ``manifest-rev`` to point at the ``v2.0.0`` tag +- import :file:`zephyr/west.yml` at that ``manifest-rev`` +- locally check out the ``v2.0.0`` revisions for all zephyr projects except + ``hal_nordic`` +- update ``hal_nordic`` to ``my-sha`` instead of ``another-sha`` -- If the value is a relative path naming a directory (or a map whose ``file`` - is a directory), the manifest files it contains are processed in - lexicographic order -- i.e., sorted by file name. -- If the value is a sequence, its elements are recursively imported in the - order they appear. +.. _west-manifest-import-path: -.. _west-manifest-groups: +Option 2: Relative path +======================= -Project Groups and Active Projects -********************************** +The ``import`` value can also be a relative path to a manifest file or a +directory containing manifest files. The path is relative to the root directory +of the ``projects`` or ``self`` repository the ``import`` key appears in. -You can use the ``groups`` and ``group-filter`` keys briefly described -:ref:`above ` to place projects into groups, and filter -which groups are enabled. These keys appear in the manifest like this: +Here is an example: .. code-block:: yaml manifest: projects: - - name: some-project - groups: ... - group-filter: ... - -You can enable or disable project groups using ``group-filter``. Projects whose -groups are all disabled are *inactive*; west essentially ignores inactive -projects unless explicitly requested not to. + - name: project-1 + revision: v1.0 + import: west.yml + - name: project-2 + revision: master + import: p2-manifests + self: + import: submanifests -The next section introduces project groups; the following sections describe -:ref:`west-enabled-disabled-groups` and :ref:`west-active-inactive-projects`. -Finally, there are :ref:`west-project-group-examples`. +This will import the following: -Project Groups -============== +- the contents of :file:`project-1/west.yml` at ``manifest-rev``, which points + at tag ``v1.0`` after running ``west update`` +- any YAML files in the directory tree :file:`project-2/p2-manifests` + at the latest ``master``, as fetched by ``west update``, sorted by file name +- YAML files in :file:`submanifests` in your manifest repository, + as they appear on your file system, sorted by file name -Inside ``manifest: projects:``, you can add a project to one or more groups. -The ``groups`` key is a list of group names. Group names are strings. +Notice how ``projects`` imports get data from Git using ``manifest-rev``, while +``self`` imports get data from your file system. This is because as usual, west +leaves version control for your manifest repository up to you. -For example, in this manifest fragment: +.. _west-manifest-ex2.1: -.. code-block:: yaml +Example 2.1: Downstream of a Zephyr release with explicit path +-------------------------------------------------------------- - manifest: - projects: - - name: project-1 - groups: - - groupA - - name: project-2 - groups: - - groupB - - groupC - - name: project-3 +This is an explicit way to write an equivalent manifest to the one in +:ref:`west-manifest-ex1.1`. -The projects are in these groups: +.. code-block:: yaml -- ``project-1``: one group, named ``groupA`` -- ``project-2``: two groups, named ``groupB`` and ``groupC`` -- ``project-3``: no groups + manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v1.14.1 + import: west.yml -Project group names must not contain commas (,), colons (:), or whitespace. +The setting ``import: west.yml`` means to use the file :file:`west.yml` inside +the ``zephyr`` project. This example is contrived, but shows the idea. -Group names must not begin with a dash (-) or the plus sign (+), but they may -contain these characters elsewhere in their names. For example, ``foo-bar`` and -``foo+bar`` are valid groups, but ``-foobar`` and ``+foobar`` are not. +This can be useful in practice when the name of the manifest file you want to +import is not :file:`west.yml`. -Group names are otherwise arbitrary strings. Group names are case sensitive. +.. _west-manifest-ex2.2: -As a restriction, no project may use both ``import:`` and ``groups:``. (This -avoids some edge cases whose semantics are difficult to specify.) +Example 2.2: Downstream with directory of manifest files +-------------------------------------------------------- -.. _west-enabled-disabled-groups: +Your Zephyr downstream has a lot of additional repositories. So many, in fact, +that you want to split them up into multiple manifest files, but keep track of +them all in a single manifest repository, like this: -Enabled and Disabled Project Groups -=================================== +.. code-block:: none -You can enable or disable project groups in both your manifest file and -:ref:`west-config`. + my-repo/ + ├── submanifests + │ ├── 01-libraries.yml + │ ├── 02-vendor-hals.yml + │ └── 03-applications.yml + └── west.yml -All groups are enabled by default. +You want to add all the files in :file:`my-repo/submanifests` to the main +manifest file, :file:`my-repo/west.yml`, in addition to projects in +:file:`zephyr/west.yml`. You want to track the latest mainline master +instead of using a fixed revision. -Within the manifest file, the top level ``manifest: group-filter:`` value can -be used to disable project groups. To disable a group, prefix its name with a -dash (-). For example, in this manifest fragment: +Here's how: .. code-block:: yaml + # my-repo/west.yml: manifest: - group-filter: [-groupA,-groupB] + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + import: true + self: + import: submanifests -The groups named ``groupA`` and ``groupB`` are disabled by this -``group-filter`` value. +Manifest files are imported in this order during resolution: -The ``group-filter`` list is an ordinary YAML list, so you could have also -written this fragment like this: +#. :file:`my-repo/submanifests/01-libraries.yml` +#. :file:`my-repo/submanifests/02-vendor-hals.yml` +#. :file:`my-repo/submanifests/03-applications.yml` +#. :file:`my-repo/west.yml` +#. :file:`zephyr/west.yml` -.. code-block:: yaml +.. note:: - manifest: - group-filter: - - -groupA - - -groupB + The :file:`.yml` file names are prefixed with numbers in this example to + make sure they are imported in the specified order. -However, this syntax is harder to read and therefore discouraged. + You can pick arbitrary names. West sorts files in a directory by name before + importing. -Although it's not an error to enable groups within ``manifest: group-filter:``, -like this: +Notice how the manifests in :file:`submanifests` are imported *before* +:file:`my-repo/west.yml` and :file:`zephyr/west.yml`. In general, an ``import`` +in the ``self`` section is processed before the manifest files in ``projects`` +and the main manifest file. -.. code-block:: yaml +This means projects defined in :file:`my-repo/submanifests` take highest +precedence. For example, if :file:`01-libraries.yml` defines ``hal_nordic``, +the project by the same name in :file:`zephyr/west.yml` is simply ignored. As +usual, see :ref:`west-manifest-resolve` for troubleshooting advice. - manifest: - ... - group-filter: [+groupA] +This may seem strange, but it allows you to redefine projects "after the fact", +as we'll see in the next example. -doing so is redundant since groups are enabled by default. +.. _west-manifest-ex2.3: -Only the **top level manifest file's** ``manifest: group-filter:`` value has -any effect. The ``manifest: group-filter:`` values in any -:ref:`imported manifests ` are ignored. +Example 2.3: Continuous Integration overrides +--------------------------------------------- -In addition to the manifest file, you can control which groups are enabled and -disabled using the ``manifest.group-filter`` configuration option. This option -is a comma-separated list of groups to enable and/or disable. +Your continuous integration system needs to fetch and test multiple +repositories in your west workspace from a developer's forks instead of your +mainline development trees, to see if the changes all work well together. -To enable a group, add its name to the list prefixed with ``+``. To disable a -group, add its name prefixed with ``-``. For example, setting -``manifest.group-filter`` to ``+groupA,-groupB`` enables ``groupA``, and -disables ``groupB``. +Starting with :ref:`west-manifest-ex2.2`, the CI scripts add a +file :file:`00-ci.yml` in :file:`my-repo/submanifests`, with these contents: -The value of the configuration option overrides any data in the manifest file. -You can think of this as if the ``manifest.group-filter`` configuration option -is appended to the ``manifest: group-filter:`` list from YAML, with "last entry -wins" semantics. +.. code-block:: yaml -.. _west-active-inactive-projects: + # my-repo/submanifests/00-ci.yml: + manifest: + projects: + - name: a-vendor-hal + url: https://github.com/a-developer/hal + revision: a-pull-request-branch + - name: an-application + url: https://github.com/a-developer/application + revision: another-pull-request-branch -Active and Inactive Projects -============================ +The CI scripts run ``west update`` after generating this file in +:file:`my-repo/submanifests`. The projects defined in :file:`00-ci.yml` have +higher precedence than other definitions in :file:`my-repo/submanifests`, +because the name :file:`00-ci.yml` comes before the other file names. -All projects are *active* by default. Projects with no groups are always -active. A project is *inactive* if all of its groups are disabled. This is the -only way to make a project inactive. +Thus, ``west update`` always checks out the developer's branches in the +projects named ``a-vendor-hal`` and ``an-application``, even if those same +projects are also defined elsewhere. -Most west commands that operate on projects will ignore inactive projects by -default. For example, :ref:`west-update` when run without arguments will not -update inactive projects. As another example, running ``west list`` without -arguments will not print information for inactive projects. +.. _west-manifest-import-map: -.. _west-project-group-examples: +Option 3: Mapping +================= -Project Group Examples -====================== +The ``import`` key can also contain a mapping with the following keys: -This section contains example situations involving project groups and active -projects. The examples use both ``manifest: group-filter:`` YAML lists and -``manifest.group-filter`` configuration lists, to show how they work together. +- ``file``: Optional. The name of the manifest file or directory to import. + This defaults to :file:`west.yml` if not present. +- ``name-allowlist``: Optional. If present, a name or sequence of project names + to include. +- ``path-allowlist``: Optional. If present, a path or sequence of project paths + to match against. This is a shell-style globbing pattern, currently + implemented with `pathlib`_. Note that this means case sensitivity is + platform specific. +- ``name-blocklist``: Optional. Like ``name-allowlist``, but contains project + names to exclude rather than include. +- ``path-blocklist``: Optional. Like ``path-allowlist``, but contains project + paths to exclude rather than include. +- ``path-prefix``: Optional (new in v0.8.0). If given, this will be prepended + to the project's path in the workspace, as well as the paths of any imported + projects. This can be used to place these projects in a subdirectory of the + workspace. + +.. _re: https://docs.python.org/3/library/re.html +.. _pathlib: + https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.match + +Allowlists override blocklists if both are given. For example, if a project is +blocked by path, then allowed by name, it will still be imported. -Note that the ``defaults`` and ``remotes`` data in the following manifests -isn't relevant except to make the examples complete and self-contained. +.. _west-manifest-ex3.1: -Example 1: no disabled groups ------------------------------ +Example 3.1: Downstream with name allowlist +------------------------------------------- -The entire manifest file is: +Here is a pair of manifest files, representing a mainline and a +downstream. The downstream doesn't want to use all the mainline +projects, however. We'll assume the mainline :file:`west.yml` is +hosted at ``https://git.example.com/mainline/manifest``. .. code-block:: yaml + # mainline west.yml: manifest: projects: - - name: foo - groups: - - groupA - - name: bar - groups: - - groupA - - groupB - - name: baz - - defaults: - remote: example-remote - remotes: - - name: example-remote - url-base: https://git.example.com - -The ``manifest.group-filter`` configuration option is not set (you can ensure -this by running ``west config -D manifest.group-filter``). - -No groups are disabled, because all groups are enabled by default. Therefore, -all three projects (``foo``, ``bar``, and ``baz``) are active. Note that there -is no way to make project ``baz`` inactive, since it has no groups. + - name: mainline-app # included + path: examples/app + url: https://git.example.com/mainline/app + - name: lib + path: libraries/lib + url: https://git.example.com/mainline/lib + - name: lib2 # included + path: libraries/lib2 + url: https://git.example.com/mainline/lib2 -Example 2: Disabling one group via manifest -------------------------------------------- + # downstream west.yml: + manifest: + projects: + - name: mainline + url: https://git.example.com/mainline/manifest + import: + name-allowlist: + - mainline-app + - lib2 + - name: downstream-app + url: https://git.example.com/downstream/app + - name: lib3 + path: libraries/lib3 + url: https://git.example.com/downstream/lib3 -The entire manifest file is: +An equivalent manifest in a single file would be: .. code-block:: yaml manifest: projects: - - name: foo - groups: - - groupA - - name: bar - groups: - - groupA - - groupB - - group-filter: [-groupA] - - defaults: - remote: example-remote - remotes: - - name: example-remote - url-base: https://git.example.com + - name: mainline + url: https://git.example.com/mainline/manifest + - name: downstream-app + url: https://git.example.com/downstream/app + - name: lib3 + path: libraries/lib3 + url: https://git.example.com/downstream/lib3 + - name: mainline-app # imported + path: examples/app + url: https://git.example.com/mainline/app + - name: lib2 # imported + path: libraries/lib2 + url: https://git.example.com/mainline/lib2 -The ``manifest.group-filter`` configuration option is not set (you can ensure -this by running ``west config -D manifest.group-filter``). +If an allowlist had not been used, the ``lib`` project from the mainline +manifest would have been imported. -Since ``groupA`` is disabled, project ``foo`` is inactive. Project ``bar`` is -active, because ``groupB`` is enabled. +.. _west-manifest-ex3.2: -Example 3: Disabling multiple groups via manifest -------------------------------------------------- +Example 3.2: Downstream with path allowlist +------------------------------------------- -The entire manifest file is: +Here is an example showing how to allowlist mainline's libraries only, +using ``path-allowlist``. .. code-block:: yaml + # mainline west.yml: manifest: projects: - - name: foo - groups: - - groupA - - name: bar - groups: - - groupA - - groupB + - name: app + path: examples/app + url: https://git.example.com/mainline/app + - name: lib + path: libraries/lib # included + url: https://git.example.com/mainline/lib + - name: lib2 + path: libraries/lib2 # included + url: https://git.example.com/mainline/lib2 - group-filter: [-groupA,-groupB] + # downstream west.yml: + manifest: + projects: + - name: mainline + url: https://git.example.com/mainline/manifest + import: + path-allowlist: libraries/* + - name: app + url: https://git.example.com/downstream/app + - name: lib3 + path: libraries/lib3 + url: https://git.example.com/downstream/lib3 - defaults: - remote: example-remote - remotes: - - name: example-remote - url-base: https://git.example.com +An equivalent manifest in a single file would be: -The ``manifest.group-filter`` configuration option is not set (you can ensure -this by running ``west config -D manifest.group-filter``). +.. code-block:: yaml -Both ``foo`` and ``bar`` are inactive, because all of their groups are -disabled. + manifest: + projects: + - name: lib # imported + path: libraries/lib + url: https://git.example.com/mainline/lib + - name: lib2 # imported + path: libraries/lib2 + url: https://git.example.com/mainline/lib2 + - name: mainline + url: https://git.example.com/mainline/manifest + - name: app + url: https://git.example.com/downstream/app + - name: lib3 + path: libraries/lib3 + url: https://git.example.com/downstream/lib3 -Example 4: Disabling a group via configuration ----------------------------------------------- +.. _west-manifest-ex3.3: -The entire manifest file is: +Example 3.3: Downstream with path blocklist +------------------------------------------- + +Here's an example showing how to block all vendor HALs from mainline by +common path prefix in the workspace, add your own version for the chip +you're targeting, and keep everything else. .. code-block:: yaml + # mainline west.yml: manifest: - projects: - - name: foo - groups: - - groupA - - name: bar - groups: - - groupA - - groupB - defaults: - remote: example-remote + remote: mainline remotes: - - name: example-remote - url-base: https://git.example.com - -The ``manifest.group-filter`` configuration option is set to ``-groupA`` (you -can ensure this by running ``west config manifest.group-filter -- -groupA``; -the extra ``--`` is required so the argument parser does not treat ``-groupA`` -as a command line option ``-g`` with value ``roupA``). - -Project ``foo`` is inactive because ``groupA`` has been disabled by the -``manifest.group-filter`` configuration option. Project ``bar`` is active -because ``groupB`` is enabled. + - name: mainline + url-base: https://git.example.com/mainline + projects: + - name: app + - name: lib + path: libraries/lib + - name: lib2 + path: libraries/lib2 + - name: hal_foo + path: modules/hals/foo # excluded + - name: hal_bar + path: modules/hals/bar # excluded + - name: hal_baz + path: modules/hals/baz # excluded -Example 5: Overriding a disabled group via configuration --------------------------------------------------------- + # downstream west.yml: + manifest: + projects: + - name: mainline + url: https://git.example.com/mainline/manifest + import: + path-blocklist: modules/hals/* + - name: hal_foo + path: modules/hals/foo + url: https://git.example.com/downstream/hal_foo -The entire manifest file is: +An equivalent manifest in a single file would be: .. code-block:: yaml manifest: - projects: - - name: foo - - name: bar - groups: - - groupA - - name: baz - groups: - - groupA - - groupB - - group-filter: [-groupA] - defaults: - remote: example-remote + remote: mainline remotes: - - name: example-remote - url-base: https://git.example.com - -The ``manifest.group-filter`` configuration option is set to ``+groupA`` (you -can ensure this by running ``west config manifest.group-filter +groupA``). + - name: mainline + url-base: https://git.example.com/mainline + projects: + - name: app # imported + - name: lib # imported + path: libraries/lib + - name: lib2 # imported + path: libraries/lib2 + - name: mainline + repo-path: https://git.example.com/mainline/manifest + - name: hal_foo + path: modules/hals/foo + url: https://git.example.com/downstream/hal_foo -In this case, ``groupA`` is enabled: the ``manifest.group-filter`` -configuration option has higher precedence than the ``manifest: group-filter: -[-groupA]`` content in the manifest file. +.. _west-manifest-ex3.4: -Therefore, projects ``foo`` and ``bar`` are both active. +Example 3.4: Import into a subdirectory +--------------------------------------- -Example 6: Overriding multiple disabled groups via configuration ----------------------------------------------------------------- +You want to import a manifest and its projects, placing everything into a +subdirectory of your :term:`west workspace`. -The entire manifest file is: +For example, suppose you want to import this manifest from project ``foo``, +adding this project and its projects ``bar`` and ``baz`` to your workspace: .. code-block:: yaml + # foo/west.yml: manifest: + defaults: + remote: example + remotes: + - name: example + url-base: https://git.example.com projects: - - name: foo - name: bar - groups: - - groupA - name: baz - groups: - - groupA - - groupB - group-filter: [-groupA,-groupB] +Instead of importing these into the top level workspace, you want to place all +three project repositories in an :file:`external-code` subdirectory, like this: - defaults: - remote: example-remote - remotes: - - name: example-remote - url-base: https://git.example.com +.. code-block:: none -The ``manifest.group-filter`` configuration option is set to -``+groupA,+groupB`` (you can ensure this by running ``west config -manifest.group-filter "+groupA,+groupB"``). + workspace/ + └── external-code/ + ├── foo/ + ├── bar/ + └── baz/ -In this case, both ``groupA`` and ``groupB`` are enabled, because the -configuration value overrides the manifest file for both groups. +You can do this using this manifest: -Therefore, projects ``foo`` and ``bar`` are both active. +.. code-block:: yaml -Example 7: Disabling multiple groups via configuration ------------------------------------------------------- + manifest: + projects: + - name: foo + url: https://git.example.com/foo + import: + path-prefix: external-code -The entire manifest file is: +An equivalent manifest in a single file would be: .. code-block:: yaml + # foo/west.yml: manifest: + defaults: + remote: example + remotes: + - name: example + url-base: https://git.example.com projects: - name: foo + path: external-code/foo - name: bar - groups: - - groupA + path: external-code/bar - name: baz - groups: - - groupA - - groupB + path: external-code/baz - defaults: - remote: example-remote - remotes: - - name: example-remote - url-base: https://git.example.com +.. _west-manifest-import-seq: -The ``manifest.group-filter`` configuration option is set to -``-groupA,-groupB`` (you can ensure this by running ``west config -manifest.group-filter -- "-groupA,-groupB"``). +Option 4: Sequence +================== -In this case, both ``groupA`` and ``groupB`` are disabled. +The ``import`` key can also contain a sequence of files, directories, +and mappings. -Therefore, projects ``foo`` and ``bar`` are both inactive. +.. _west-manifest-ex4.1: -.. _west-manifest-submodules: +Example 4.1: Downstream with sequence of manifest files +------------------------------------------------------- -Git Submodules in Projects -************************** +This example manifest is equivalent to the manifest in +:ref:`west-manifest-ex2.2`, with a sequence of explicitly named files. -You can use the ``submodules`` keys briefly described :ref:`above -` to force ``west update`` to also handle any `Git -submodules`_ configured in project's git repository. The ``submodules`` key can -appear inside ``projects``, like this: +.. code-block:: yaml -.. code-block:: YAML + # my-repo/west.yml: + manifest: + projects: + - name: zephyr + url: https://github.com/zephyrproject-rtos/zephyr + import: west.yml + self: + import: + - submanifests/01-libraries.yml + - submanifests/02-vendor-hals.yml + - submanifests/03-applications.yml + +.. _west-manifest-ex4.2: + +Example 4.2: Import order illustration +-------------------------------------- + +This more complicated example shows the order that west imports manifest files: +.. code-block:: yaml + + # my-repo/west.yml manifest: + # ... projects: - - name: some-project - submodules: ... + - name: my-library + - name: my-app + - name: zephyr + import: true + - name: another-manifest-repo + import: submanifests + self: + import: + - submanifests/libraries.yml + - submanifests/vendor-hals.yml + - submanifests/applications.yml + defaults: + remote: my-remote -The ``submodules`` key can be a boolean or a list of mappings. We'll describe -these in order. +For this example, west resolves imports in this order: -Option 1: Boolean -================= +#. the listed files in :file:`my-repo/submanifests` are first, in the order + they occur (e.g. :file:`libraries.yml` comes before + :file:`applications.yml`, since this is a sequence of files), since the + ``self: import:`` is always imported first +#. :file:`my-repo/west.yml` is next (with projects ``my-library`` etc. as long + as they weren't already defined somewhere in :file:`submanifests`) +#. :file:`zephyr/west.yml` is after that, since that's the first ``import`` key + in the ``projects`` list in :file:`my-repo/west.yml` +#. files in :file:`another-manifest-repo/submanifests` are last (sorted by file + name), since that's the final project ``import`` -This is the easiest way to use ``submodules``. +.. _west-manifest-formal: -If ``submodules`` is ``true`` as a ``projects`` attribute, ``west update`` will -recursively update the project's Git submodules whenever it updates the project -itself. If it's ``false`` or missing, it has no effect. +Manifest Import Details +======================= -For example, let's say you have a source code repository ``foo``, which has -some submodules, and you want ``west update`` to keep all of them them in sync, -along with another project named ``bar`` in the same workspace. +This section describes how west imports a manifest file a bit more formally. -You can do that with this manifest file: +Overview +-------- + +A west manifest's ``projects`` and ``self`` sections can have ``import`` keys, +like so: .. code-block:: yaml + # Top-level west.yml. manifest: + # ... projects: - name: foo - submodules: true + revision: rev-1 + import: import-1 - name: bar + revision: rev-2 + import: import-2 + # ... + - name: baz + revision: rev-N + import: import-N + self: + import: self-import -Here, ``west update`` will initialize and update all submodules in ``foo``. If -``bar`` has any submodules, they are ignored, because ``bar`` does not have a -``submodules`` value. +Import keys are optional. If any of ``import-1, ..., import-N`` are missing, +west will not import additional manifest data from that project. If +``self-import`` is missing, no additional files in the manifest repository +(beyond the top-level west.yml) are imported. -Option 2: List of mappings -========================== +The ultimate outcome of resolving manifest imports is a final list of projects, +which is produced by combining the ``projects`` defined in the top-level file +with those defined in imported files. Importing is done in this order: -The ``submodules`` key may be a list of mappings. Each element in the list -defines the name of the submodule to update, and the path -- relative to the -project's absolute path in the workspace -- to use for the submodule. -The submodule will be updated recursively. +#. Manifests from ``self-import`` are imported first. +#. The top-level manifest file's ``projects`` are added in next. +#. Manifests from ``import-1``, ..., ``import-N``, are imported in that order. -For example, let's say you have a source code repository ``foo``, which has -many submodules, and you want ``west update`` to keep some but not all of them -in sync, along with another project named ``bar`` in the same workspace. +This process recurses if necessary. -You can do that with this manifest file: +Projects are identified by name. If the same name occurs in multiple manifests, +the first definition is used, and subsequent definitions are ignored. For +example, if ``import-1`` contains a project named ``bar``, that is ignored, +because the top-level :file:`west.yml` has already defined a project by that +name. -.. code-block:: yaml +The contents of files named by ``import-1`` through ``import-N`` are imported +from Git at the latest ``manifest-rev`` revisions in their projects. These +revisions can be updated to the values ``rev-1`` through ``rev-N`` by running +``west update``. If any ``manifest-rev`` reference is missing or out of date, +``west update`` also fetches project data from the remote fetch URL and updates +the reference. - manifest: - projects: - - name: foo - submodules: - - name: foo-first-sub - path: path/to/foo-first-sub - - name: foo-second-sub - path: path/to/foo-second-sub - - name: bar +Also note that all imported manifests, from the root manifest to the repository +which defines a project ``P``, must be up to date in order for west to update +``P`` itself. For example, this means ``west update P`` would update +``manifest-rev`` in the ``baz`` project if :file:`baz/west.yml` defines ``P``, +as well as updating the ``manifest-rev`` branch in the local git clone of +``P``. Confusingly, the update of ``baz`` may result in the removal of ``P`` +from :file:`baz/west.yml`, which would cause ``west update P`` to fail with an +unrecognized project! -Here, ``west update`` will recursively initialize and update just the -submodules in ``foo`` with paths ``path/to/foo-first-sub`` and -``path/to/foo-second-sub``. Any submodules in ``bar`` are still ignored. +For this reason, it's usually best to run plain ``west update`` to avoid errors +if you use manifest imports. By default, west won't fetch any project data over +the network if a project's revision is a SHA or tag which is already available +locally, so updating the extra projects shouldn't take too much time unless +it's really needed. See the documentation for the :ref:`update.fetch +` configuration option for more information. + +If an imported manifest file has a ``west-commands:`` definition in its +``self:`` section, the extension commands defined there are added to the set of +available extensions at the time the manifest is imported. They will thus take +precedence over any extension commands with the same names added later on. + +When an individual ``import`` key refers to multiple manifest files, they are +processed in this order: + +- If the value is a relative path naming a directory (or a map whose ``file`` + is a directory), the manifest files it contains are processed in + lexicographic order -- i.e., sorted by file name. +- If the value is a sequence, its elements are recursively imported in the + order they appear. .. _west-manifest-cmd: From decfe37b4e1ec5152290121e6f41175a31dbc30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 16 Feb 2021 15:29:14 -0800 Subject: [PATCH 104/226] doc: west: fix incorrect docs related to imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation suggests that 'west update PROJECT' can be done if PROJECT is defined from some imported manifest. That's actually not true. Fix it. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index b3acd0ba..42e8e115 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -1713,16 +1713,19 @@ which defines a project ``P``, must be up to date in order for west to update ``P`` itself. For example, this means ``west update P`` would update ``manifest-rev`` in the ``baz`` project if :file:`baz/west.yml` defines ``P``, as well as updating the ``manifest-rev`` branch in the local git clone of -``P``. Confusingly, the update of ``baz`` may result in the removal of ``P`` -from :file:`baz/west.yml`, which would cause ``west update P`` to fail with an +``P``. Confusingly, updating ``baz`` may result in the removal of ``P`` +from :file:`baz/west.yml`, which "should" cause ``west update P`` to fail with an unrecognized project! -For this reason, it's usually best to run plain ``west update`` to avoid errors -if you use manifest imports. By default, west won't fetch any project data over -the network if a project's revision is a SHA or tag which is already available -locally, so updating the extra projects shouldn't take too much time unless -it's really needed. See the documentation for the :ref:`update.fetch -` configuration option for more information. +For this reason, it's not possible to run ``west update P`` if ``P`` is defined +in an imported manifest; you must update this project along with all the others +with a plain ``west update``. + +By default, west won't fetch any project data over the network if a project's +revision is a SHA or tag which is already available locally, so updating the +extra projects shouldn't take too much time unless it's really needed. See the +documentation for the :ref:`update.fetch ` configuration +option for more information. If an imported manifest file has a ``west-commands:`` definition in its ``self:`` section, the extension commands defined there are added to the set of From 50a8d41652c8d6914914841f74b646e3d041ab88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 16 Feb 2021 15:39:42 -0800 Subject: [PATCH 105/226] doc: west: clean up manifest import details MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the content related to handling imports that refer to multiple files handled to right after the ordered list which defines the order that manifests are imported. The current placement at the end of this docs section was poorly chosen. Create subsections for how projects and extensions are decided in the final resolved manifest. The project revisions in the top level example manifest fragment are not important here. Remove them for clarity. The top level manifest file need not be named west.yml now; adjust accordingly. This is prep work for adding a new subsection for group-filter. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 62 +++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 42e8e115..2dadcbd8 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -1653,29 +1653,26 @@ For this example, west resolves imports in this order: Manifest Import Details ======================= -This section describes how west imports a manifest file a bit more formally. +This section describes how west resolves a manifest file that uses ``import`` a +bit more formally. Overview -------- -A west manifest's ``projects`` and ``self`` sections can have ``import`` keys, -like so: +The ``import`` key can appear in a west manifest's ``projects`` and ``self`` +sections. The general case looks like this: .. code-block:: yaml - # Top-level west.yml. + # Top-level manifest file. manifest: - # ... projects: - name: foo - revision: rev-1 import: import-1 - name: bar - revision: rev-2 import: import-2 # ... - name: baz - revision: rev-N import: import-N self: import: self-import @@ -1683,17 +1680,39 @@ like so: Import keys are optional. If any of ``import-1, ..., import-N`` are missing, west will not import additional manifest data from that project. If ``self-import`` is missing, no additional files in the manifest repository -(beyond the top-level west.yml) are imported. +(beyond the top-level file) are imported. + +The ultimate outcomes of resolving manifest imports are: + +- a ``projects`` list, which is produced by combining the ``projects`` defined + in the top-level file with those defined in imported files + +- a set of extension commands, which are drawn from the the ``west-commands`` + keys in in the top-level file and any imported files -The ultimate outcome of resolving manifest imports is a final list of projects, -which is produced by combining the ``projects`` defined in the top-level file -with those defined in imported files. Importing is done in this order: +Importing is done in this order: #. Manifests from ``self-import`` are imported first. -#. The top-level manifest file's ``projects`` are added in next. +#. The top-level manifest file's definitions are handled next. #. Manifests from ``import-1``, ..., ``import-N``, are imported in that order. -This process recurses if necessary. +When an individual ``import`` key refers to multiple manifest files, they are +processed in this order: + +- If the value is a relative path naming a directory (or a map whose ``file`` + is a directory), the manifest files it contains are processed in + lexicographic order -- i.e., sorted by file name. +- If the value is a sequence, its elements are recursively imported in the + order they appear. + +This process recurses if necessary. E.g., if ``import-1`` produces a manifest +file that contains an ``import`` key, it is resolved recursively using the same +rules before its contents are processed further. + +Projects +-------- + +This section describes how the final ``projects`` list is created. Projects are identified by name. If the same name occurs in multiple manifests, the first definition is used, and subsequent definitions are ignored. For @@ -1727,20 +1746,17 @@ extra projects shouldn't take too much time unless it's really needed. See the documentation for the :ref:`update.fetch ` configuration option for more information. +Extensions +---------- + +All extension commands defined using ``west-commands`` keys discovered while +handling imports are available in the resolved manifest. + If an imported manifest file has a ``west-commands:`` definition in its ``self:`` section, the extension commands defined there are added to the set of available extensions at the time the manifest is imported. They will thus take precedence over any extension commands with the same names added later on. -When an individual ``import`` key refers to multiple manifest files, they are -processed in this order: - -- If the value is a relative path naming a directory (or a map whose ``file`` - is a directory), the manifest files it contains are processed in - lexicographic order -- i.e., sorted by file name. -- If the value is a sequence, its elements are recursively imported in the - order they appear. - .. _west-manifest-cmd: Manifest Command From 4ae83e91ac0b7133c7d4516ebddf6e9ff251fa4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 16 Feb 2021 16:19:48 -0800 Subject: [PATCH 106/226] doc: west: document west 0.10 group-filter + import behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The west 0.9 documentation for group-filter states: Only the top level manifest file’s manifest: group-filter: value has any effect. The manifest: group-filter: values in any imported manifests are ignored. This turns out to have been a mistake, because all users who import a manifest which makes some projects inactive will have to also manually disable the same groups just to get the same default list of projects. Example manifest fragments showing the issue: # my/west.yml manifest: projects: - name: upstream import: true and: # upstream/west.yml manifest: group-filter: [-disabled-group] projects: - name: i-want-this - name: i-do-not-want-this groups: - disabled-group As written, my/west.yml will include 'i-do-not-want-this' as an active project. This kind of leaky faucet has proven to be an unintuitive and poor user experience. Users expect to get the default projects without having to copy the group-filter for everything they import. We can't reverse this behavior without pushing out a new schema version, however: manifest schema 0.9, and therefore west 0.9.x, is doomed to this bad behavior. What we'll do to move past this is create a new schema version 0.10 that does the right thing, document the 0.10 behavior, and discourage combining these two features in west 0.9.x. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 262 +++++++++++++++++++++++++++++++---- 1 file changed, 235 insertions(+), 27 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 2dadcbd8..a5c745e1 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -432,7 +432,10 @@ projects unless explicitly requested not to. The next section introduces project groups; the following sections describe :ref:`west-enabled-disabled-groups` and :ref:`west-active-inactive-projects`. -Finally, there are :ref:`west-project-group-examples`. +There are some basic examples in :ref:`west-project-group-examples`. + +Finally, :ref:`west-group-filter-imports` provides a simplified overview of how +``group-filter`` interacts with the :ref:`west-manifest-import` feature. Project Groups ============== @@ -477,49 +480,45 @@ avoids some edge cases whose semantics are difficult to specify.) Enabled and Disabled Project Groups =================================== -You can enable or disable project groups in both your manifest file and -:ref:`west-config`. +All project groups are enabled by default. You can enable or disable groups in +both your manifest file and :ref:`west-config`. -All groups are enabled by default. +Within a manifest file, ``manifest: group-filter:`` is a YAML list of groups to +enable and disable. -Within the manifest file, the top level ``manifest: group-filter:`` value can -be used to disable project groups. To disable a group, prefix its name with a -dash (-). For example, in this manifest fragment: +To enable a group, prefix its name with a plus sign (+). For example, +``groupA`` is enabled in this manifest fragment: .. code-block:: yaml manifest: - group-filter: [-groupA,-groupB] + group-filter: [+groupA] -The groups named ``groupA`` and ``groupB`` are disabled by this -``group-filter`` value. +Although this is redundant for groups that are already enabled by default, it +can be used to override settings in an imported manifest file. See +:ref:`west-group-filter-imports` for more information. -The ``group-filter`` list is an ordinary YAML list, so you could have also -written this fragment like this: +To disable a group, prefix its name with a dash (-). For example, ``groupA`` +and ``groupB`` are disabled in this manifest fragment: .. code-block:: yaml manifest: - group-filter: - - -groupA - - -groupB + group-filter: [-groupA,-groupB] -However, this syntax is harder to read and therefore discouraged. +.. note:: -Although it's not an error to enable groups within ``manifest: group-filter:``, -like this: + Since ``group-filter`` is a YAML list, you could have written this fragment + as follows: -.. code-block:: yaml + .. code-block:: yaml - manifest: - ... - group-filter: [+groupA] - -doing so is redundant since groups are enabled by default. + manifest: + group-filter: + - -groupA + - -groupB -Only the **top level manifest file's** ``manifest: group-filter:`` value has -any effect. The ``manifest: group-filter:`` values in any -:ref:`imported manifests ` are ignored. + However, this syntax is harder to read and therefore discouraged. In addition to the manifest file, you can control which groups are enabled and disabled using the ``manifest.group-filter`` configuration option. This option @@ -788,6 +787,175 @@ In this case, both ``groupA`` and ``groupB`` are disabled. Therefore, projects ``foo`` and ``bar`` are both inactive. +.. _west-group-filter-imports: + +Group Filters and Imports +========================= + +This section provides a simplified description of how the ``manifest: +group-filter:`` value behaves when combined with :ref:`west-manifest-import`. +For complete details, see :ref:`west-manifest-formal`. + +.. warning:: + + The below semantics apply to west v0.10.0 and later. West v0.9.x semantics + are different, and combining ``group-filter`` with ``import`` in west v0.9.x + is discouraged. + +In short: + +- if you only import one manifest, any groups it disables in its + ``group-filter`` are also disabled in your manifest +- you can override this in your manifest file's ``manifest: group-filter:`` + value, your workspace's ``manifest.group-filter`` configuration option, or + both + +Here are some examples. + +Example 1: no overrides +----------------------- + +You are using this :file:`parent/west.yml` manifest: + +.. code-block:: yaml + + # parent/west.yml: + manifest: + projects: + - name: child + url: https://git.example.com/child + import: true + - name: project-1 + url: https://git.example.com/project-1 + groups: + - unstable + +And :file:`child/west.yml` contains: + +.. code-block:: yaml + + # child/west.yml: + manifest: + group-filter: [-unstable] + projects: + - name: project-2 + url: https://git.example.com/project-2 + - name: project-3 + url: https://git.example.com/project-3 + groups: + - unstable + +Only ``child`` and ``project-2`` are active in the resolved manifest. + +The ``unstable`` group is disabled in :file:`child/west.yml`, and that is not +overridden in :file:`parent/west.yml`. Therefore, the final ``group-filter`` +for the resolved manifest is ``[-unstable]``. + +Since ``project-1`` and ``project-3`` are in the ``unstable`` group and are not +in any other group, they are inactive. + +Example 2: overriding an imported ``group-filter`` via manifest +--------------------------------------------------------------- + +You are using this :file:`parent/west.yml` manifest: + +.. code-block:: yaml + + # parent/west.yml: + manifest: + group-filter: [+unstable,-optional] + projects: + - name: child + url: https://git.example.com/child + import: true + - name: project-1 + url: https://git.example.com/project-1 + groups: + - unstable + +And :file:`child/west.yml` contains: + +.. code-block:: yaml + + # child/west.yml: + manifest: + group-filter: [-unstable] + projects: + - name: project-2 + url: https://git.example.com/project-2 + groups: + - optional + - name: project-3 + url: https://git.example.com/project-3 + groups: + - unstable + +Only the ``child``, ``project-1``, and ``project-3`` projects are active. + +The ``[-unstable]`` group filter in :file:`child/west.yml` is overridden in +:file:`parent/west.yml`, so the ``unstable`` group is enabled. Since +``project-1`` and ``project-3`` are in the ``unstable`` group, they are active. + +The same :file:`parent/west.yml` file disables the ``optional`` group, so +``project-2`` is inactive. + +The final group filter specified by :file:`parent/west.yml` is +``[+unstable,-optional]``. + +Example 3: overriding an imported ``group-filter`` via configuration +-------------------------------------------------------------------- + +You are using this :file:`parent/west.yml` manifest: + +.. code-block:: yaml + + # parent/west.yml: + manifest: + projects: + - name: child + url: https://git.example.com/child + import: true + - name: project-1 + url: https://git.example.com/project-1 + groups: + - unstable + +And :file:`child/west.yml` contains: + +.. code-block:: yaml + + # child/west.yml: + manifest: + group-filter: [-unstable] + projects: + - name: project-2 + url: https://git.example.com/project-2 + groups: + - optional + - name: project-3 + url: https://git.example.com/project-3 + groups: + - unstable + +If you run: + +.. code-block:: shell + + west config manifest.group-filter +unstable,-optional + +Then only the ``child``, ``project-1``, and ``project-3`` projects are active. + +The ``-unstable`` group filter in :file:`child/west.yml` is overridden in the +``manifest.group-filter`` configuration option, so the ``unstable`` group is +enabled. Since ``project-1`` and ``project-3`` are in the ``unstable`` group, +they are active. + +The same configuration option disables the ``optional`` group, so ``project-2`` +is inactive. + +The final group filter specified by :file:`parent/west.yml` and the +``manifest.group-filter`` configuration option is ``[+unstable,-optional]``. + .. _west-manifest-submodules: Git Submodules in Projects @@ -1690,6 +1858,9 @@ The ultimate outcomes of resolving manifest imports are: - a set of extension commands, which are drawn from the the ``west-commands`` keys in in the top-level file and any imported files +- a ``group-filter`` list, which is produced by combining the top-level and any + imported filters + Importing is done in this order: #. Manifests from ``self-import`` are imported first. @@ -1757,6 +1928,43 @@ If an imported manifest file has a ``west-commands:`` definition in its available extensions at the time the manifest is imported. They will thus take precedence over any extension commands with the same names added later on. +Group filters +------------- + +The resolved manifest has a ``group-filter`` value which is the result of +concatenating the ``group-filter`` values in the top-level manifest and any +imported manifests. + +Manifest files which appear earlier in the import order have higher precedence +and are therefore concatenated later into the final ``group-filter``. + +In other words, let: + +- the submanifest resolved from ``self-import`` have group filter ``self-filter`` +- the top-level manifest file have group filter ``top-filter`` +- the submanifests resolved from ``import-1`` through ``import-N`` have group + filters ``filter-1`` through ``filter-N`` respectively + +The final resolved ``group-filter`` value is then ``filter1 + filter-2 + ... + +filter-N + top-filter + self-filter``, where ``+`` here refers to list +concatenation. + +.. important:: + + The order that filters appear in the above list matters. + + The last filter element in the final concatenated list "wins" and determines + if the group is enabled or disabled. + +For example, in ``[-foo] + [+foo]``, group ``foo`` is *enabled*. +However, in ``[+foo] + [-foo]``, group ``foo`` is *disabled*. + +For simplicity, west and this documentation may elide concatenated group filter +elements which are redundant using these rules. For example, ``[+foo] + +[-foo]`` could be written more simply as ``[-foo]``, for the reasons given +above. As another example, ``[-foo] + [+foo]`` could be written as the empty +list ``[]``, since all groups are enabled by default. + .. _west-manifest-cmd: Manifest Command From ad437c630af465025b90e91aa396e72f2f0838ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 1 Mar 2021 11:43:09 -0800 Subject: [PATCH 107/226] doc: west: projects list is optional in v0.10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document this fact. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index a5c745e1..de0cf084 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -81,17 +81,17 @@ with some subsections, like this: manifest: remotes: - # short names for project URLs (optional) + # short names for project URLs projects: - # a list of projects managed by west (mandatory) + # a list of projects managed by west defaults: - # default project attributes (optional) + # default project attributes self: # configuration related to the manifest repository itself, - # i.e. the repository containing west.yml (optional) - version: # optional + # i.e. the repository containing west.yml + version: group-filter: - # a list of project groups to enable or disable (optional) + # a list of project groups to enable or disable In YAML terms, the manifest file contains a mapping, with a ``manifest`` key. Any other keys and their contents are ignored (west v0.5 also required a @@ -99,8 +99,12 @@ key. Any other keys and their contents are ignored (west v0.5 also required a The manifest contains subsections, like ``defaults``, ``remotes``, ``projects``, and ``self``. In YAML terms, the value of the ``manifest`` key is -also a mapping, with these "subsections" as keys. Only ``projects`` is -mandatory: this is the list of repositories managed by west and their metadata. +also a mapping, with these "subsections" as keys. As of west v0.10, all of +these "subsection" keys are optional. + +The ``projects`` value is a list of repositories managed by west and associated +metadata. We'll discuss it soon, but first we will describe the ``remotes`` +section, which can be used to save typing in the ``projects`` list. Remotes ======= From 741700d6b7a2dca7e6aa364de1832ae2f2acdfe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 1 Mar 2021 11:43:45 -0800 Subject: [PATCH 108/226] doc: west: touch up remotes documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Try to make it a bit clearer. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index de0cf084..a2838fb8 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -110,9 +110,14 @@ Remotes ======= The ``remotes`` subsection contains a sequence which specifies the base URLs -where projects can be fetched from. Each sequence element has a name and a "URL -base". These are used to form the complete fetch URL for each project. For -example: +where projects can be fetched from. + +Each ``remotes`` element has a name and a "URL base". These are used to form +the complete Git fetch URL for each project. A project's fetch URL can be set +by appending a project-specific path onto a remote URL base. (As we'll see +below, projects can also specify their complete fetch URLs.) + +For example: .. code-block:: yaml From 10d30bee8a8fec9c2561a31790e19c92bd409e8f Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Tue, 9 Feb 2021 01:11:51 +0000 Subject: [PATCH 109/226] doc: west: submodule 'name' is optional after west 0.9.0 See west commit 02444d058335 Signed-off-by: Marc Herbert --- doc/guides/west/manifest.rst | 17 +++++++++++------ doc/guides/west/release-notes.rst | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index a2838fb8..c071fcff 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -1015,10 +1015,16 @@ Here, ``west update`` will initialize and update all submodules in ``foo``. If Option 2: List of mappings ========================== -The ``submodules`` key may be a list of mappings. Each element in the list -defines the name of the submodule to update, and the path -- relative to the -project's absolute path in the workspace -- to use for the submodule. -The submodule will be updated recursively. +The ``submodules`` key may be a list of mappings, one list element for +each desired submodule. Each submodule listed is updated recursively. +You can still track and update unlisted submodules with ``git`` commands +manually; present or not they will be completely ignored by ``west``. + +The ``path`` key must match exactly the path of one submodule relative +to its parent west project, as shown in the output of ``git submodule +status``. The ``name`` key is optional and not used by west for now; +it's not passed to ``git submodule`` commands either. The ``name`` key +was briefly mandatory in west version 0.9.0, but was made optional in 0.9.1. For example, let's say you have a source code repository ``foo``, which has many submodules, and you want ``west update`` to keep some but not all of them @@ -1032,8 +1038,7 @@ You can do that with this manifest file: projects: - name: foo submodules: - - name: foo-first-sub - path: path/to/foo-first-sub + - path: path/to/foo-first-sub - name: foo-second-sub path: path/to/foo-second-sub - name: bar diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 1c807702..9aa5ac18 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,6 +1,20 @@ West Release Notes ################## +v0.10.0 +******* + +New features: + +- A manifest file's ``group-filter`` is now propagated through an ``import``. + This is a change from how west v0.9.x handled this. In west v0.9.x, only the + top level manifest file's ``group-filter`` had any effect; the group filter + lists from any imported manifests were ignored. Starting with west v0.10.0, + the group filter lists from imported manifests are also imported. For + details, see :ref:`west-group-filter-imports`. + +- The ``name`` key in a project's submodules list is now optional. + v0.9.0 ****** @@ -10,6 +24,12 @@ v0.9.0 other manual edits in configuration files will be removed when setting a configuration option via that command or the ``west.configuration`` API. +.. warning:: + + Combining the ``group-filter`` feature introduced in this release with + manifest imports is discouraged. The resulting behavior has changed in west + v0.10. + New features: - West manifests now support :ref:`west-manifest-submodules`. This allows you From a9accf69409349f2a198a70b5b28e3f24fd3abd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 1 Mar 2021 12:07:48 -0800 Subject: [PATCH 110/226] doc: west: bump 'manifest: version:' docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust these for 0.10. This version parses differently as a string vs. as a float. Document that quoting the value avoids the issue. Make some other adjustments and improvements for clarity. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index c071fcff..2058af78 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -89,7 +89,7 @@ with some subsections, like this: self: # configuration related to the manifest repository itself, # i.e. the repository containing west.yml - version: + version: "" group-filter: # a list of project groups to enable or disable @@ -398,20 +398,25 @@ manifest file schema that can parse this file's data: .. code-block:: yaml manifest: - version: 0.7 - # marks that this manifest uses features available in west 0.7 and - # up, like manifest imports + version: "0.10" + # marks that this file uses version 0.10 of the west manifest + # file format. The pykwalify schema :file:`manifest-schema.yml` in the west source code repository is used to validate the manifest section. The current manifest -``version`` is 0.9, which corresponds to west version 0.9. +``version`` is 0.10, which is supported by west version v0.10.x. -The ``version`` value may be 0.7, 0.8, or 0.9. +The ``version`` value may be ``"0.7"``, ``"0.8"``, ``"0.9"``, or ``"0.10"``. +West v0.10.x can load manifests with any of these ``version`` values, while +west v0.9.x can only load versions up to ``"0.9"``, and so on. -If a later version of west, say version ``21.0``, includes changes to the -manifest schema that cannot be parsed by west 0.7, then setting ``version: -21.0`` will cause west to print an error when attempting to parse the manifest -data. +West halts with an error if you ask it to load a manifest file written in a +version it cannot handle. + +Quoting the ``version`` value as shown above forces the YAML parser to treat +it as a string. Without quotes, ``0.10`` in YAML is just the floating point +value ``0.1``. You can omit the quotes if the value is the same when cast to +string, but it's best to include them. Always use quotes if you're not sure. Group-filter ============ From 649c29644c9b8589182f85a20e2cb1703c426d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 1 Mar 2021 12:08:11 -0800 Subject: [PATCH 111/226] doc: west: 0.10.0 and 0.9.1 release notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Combining these since they are related. Signed-off-by: Martí Bolívar --- doc/guides/west/release-notes.rst | 43 ++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 9aa5ac18..6dfc9d14 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -6,14 +6,49 @@ v0.10.0 New features: +- The ``name`` key in a project's :ref:`submodules list + ` is now optional. + +Bug fixes: + +- West now checks that the manifest schema version is one of the explicitly + allowed vlaues documented in :ref:`west-manifest-schema-version`. The old + behavior was just to check that the schema version was newer than the west + version where the ``manifest: version:`` key was introduced. This incorrectly + allowed invalid schema versions, like ``0.8.2``. + +Other changes: + - A manifest file's ``group-filter`` is now propagated through an ``import``. This is a change from how west v0.9.x handled this. In west v0.9.x, only the top level manifest file's ``group-filter`` had any effect; the group filter - lists from any imported manifests were ignored. Starting with west v0.10.0, - the group filter lists from imported manifests are also imported. For - details, see :ref:`west-group-filter-imports`. + lists from any imported manifests were ignored. + + Starting with west v0.10.0, the group filter lists from imported manifests + are also imported. For details, see :ref:`west-group-filter-imports`. + + The new behavior will take effect if ``manifest: version:`` is not given or + is at least ``0.10``. The old behavior is still available in the top level + manifest file only with an explicit ``manifest: version: 0.9``. See + :ref:`west-manifest-schema-version` for more information on schema versions. + + See `west pull request #482 + `_ for the motivation + for this change and additional context. + +v0.9.1 +****** + +Bug fixes: + +- Commands like ``west manifest --resolve`` now correctly include group and + group filter information. + +Other changes: -- The ``name`` key in a project's submodules list is now optional. +- West now warns if you combine ``import`` with ``group-filter``. Semantics for + this combination have changed starting with v0.10.x. See the v0.10.0 release + notes above for more information. v0.9.0 ****** From 312c831175799c3939c1b0480a471306bb75dd72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 15 Mar 2021 11:22:25 -0700 Subject: [PATCH 112/226] doc: west: remove some unnecessary 'master' usages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although a project's default revision is still "master", we can change some examples around to refer to "main" branches instead, in keeping with the changes we're making for Zephyr more generally. We cannot change the default project revision away from "master" in west v0.10.x, because that would be a schema change. That will have to wait for v0.11.0. However, in the meantime, we are making some inclusive language changes related to 'west init', because the --mr option is not governed by a schema. These will be documented in the next commit. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 2058af78..6511a599 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -1213,7 +1213,7 @@ Example 1.2: "Rolling release" Zephyr downstream ------------------------------------------------ This is similar to :ref:`west-manifest-ex1.1`, except we'll use ``revision: -master`` for the zephyr repository: +main`` for the zephyr repository: .. code-block:: yaml @@ -1225,7 +1225,7 @@ master`` for the zephyr repository: projects: - name: zephyr remote: zephyrproject-rtos - revision: master + revision: main import: true You can create the workspace in the same way: @@ -1238,13 +1238,13 @@ You can create the workspace in the same way: This time, whenever you run ``west update``, the special :ref:`manifest-rev ` branch in the ``zephyr`` repository will be updated to -point at a newly fetched ``master`` branch tip from the URL +point at a newly fetched ``main`` branch tip from the URL https://github.com/zephyrproject-rtos/zephyr. The contents of :file:`zephyr/west.yml` at the new ``manifest-rev`` will then be used to import projects from Zephyr. This lets you stay up to date with the latest changes in the Zephyr project. The cost is that running ``west update`` -will not produce reproducible results, since the remote ``master`` branch can +will not produce reproducible results, since the remote ``main`` branch can change every time you run it. It's also important to understand that west **ignores your working tree's** @@ -1341,7 +1341,7 @@ Here is an example: revision: v1.0 import: west.yml - name: project-2 - revision: master + revision: main import: p2-manifests self: import: submanifests @@ -1351,7 +1351,8 @@ This will import the following: - the contents of :file:`project-1/west.yml` at ``manifest-rev``, which points at tag ``v1.0`` after running ``west update`` - any YAML files in the directory tree :file:`project-2/p2-manifests` - at the latest ``master``, as fetched by ``west update``, sorted by file name + at the latest commit in the ``main`` branch, as fetched by ``west update``, + sorted by file name - YAML files in :file:`submanifests` in your manifest repository, as they appear on your file system, sorted by file name @@ -1405,8 +1406,8 @@ them all in a single manifest repository, like this: You want to add all the files in :file:`my-repo/submanifests` to the main manifest file, :file:`my-repo/west.yml`, in addition to projects in -:file:`zephyr/west.yml`. You want to track the latest mainline master -instead of using a fixed revision. +:file:`zephyr/west.yml`. You want to track the latest development code +in the Zephyr repository's ``main`` branch instead of using a fixed revision. Here's how: @@ -1420,6 +1421,7 @@ Here's how: projects: - name: zephyr remote: zephyrproject-rtos + revision: main import: true self: import: submanifests From c2116515f1f30905f9ccc62ad2869feb5c5cb5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 15 Mar 2021 11:22:04 -0700 Subject: [PATCH 113/226] doc: west: west init --mr changes for v0.10.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See release notes for details. Signed-off-by: Martí Bolívar --- doc/guides/west/built-in.rst | 10 ++++++---- doc/guides/west/release-notes.rst | 11 +++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/built-in.rst b/doc/guides/west/built-in.rst index e5591ac3..3eb20528 100644 --- a/doc/guides/west/built-in.rst +++ b/doc/guides/west/built-in.rst @@ -52,10 +52,12 @@ and check out the ``v1.14.0`` release. This command creates ` to ``zephyr`` to record the location of the manifest repository in the workspace. The default manifest file location is used. -The ``-m`` option defaults to -``https://github.com/zephyrproject-rtos/zephyr``. The ``--mr`` option -defaults to ``master``. The ``--mf`` option defaults to ``west.yml``. If no -``directory`` is given, the current working directory is used. +The ``-m`` option defaults to ``https://github.com/zephyrproject-rtos/zephyr``. +The ``--mf`` option defaults to ``west.yml``. Since west v0.10.1, west will use +the default branch in the manifest repository unless the ``--mr`` option +is used to override it. (In prior versions, ``--mr`` defaulted to ``master``.) + +If no ``directory`` is given, the current working directory is used. **Option 2**: to create a workspace around an existing local manifest repository, use: diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 6dfc9d14..65ae43d2 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,6 +1,17 @@ West Release Notes ################## +v0.10.1 +******* + +New features: + +- The :ref:`west-init` command's ``--manifest-rev`` (``--mr``) option no longer + defaults to ``master``. Instead, the command will query the repository for + its default branch name and use that instead. This allows users to move from + ``master`` to ``main`` without breaking scripts that do not provide this + option. + v0.10.0 ******* From 388979fc4f5be313b2f896538ce70158d8832bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 6 Apr 2021 12:26:29 -0700 Subject: [PATCH 114/226] doc: west: fix submodule update info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing dashes. Signed-off-by: Martí Bolívar --- doc/guides/west/built-in.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/built-in.rst b/doc/guides/west/built-in.rst index 3eb20528..04ef48ac 100644 --- a/doc/guides/west/built-in.rst +++ b/doc/guides/west/built-in.rst @@ -204,10 +204,10 @@ with the ``--rebase`` option or without it: .. code-block:: # without --rebase, e.g. "west update": - git submodule update init --checkout --recursive + git submodule update --init --checkout --recursive # with --rebase, e.g. "west update --rebase": - git submodule update init --rebase --recursive + git submodule update --init --rebase --recursive Otherwise, the project has ``submodules: ``. In this case, west runs one of the following in the project repository for each @@ -217,10 +217,10 @@ with the ``--rebase`` option or without it: .. code-block:: # without --rebase, e.g. "west update": - git submodule update init --checkout --recursive + git submodule update --init --checkout --recursive # with --rebase, e.g. "west update --rebase": - git submodule update init --rebase --recursive + git submodule update --init --rebase --recursive .. _west-built-in-misc: From b651ee83e32072e6b1422e3bc41a0ed6793d5ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 3 May 2021 20:55:59 -0700 Subject: [PATCH 115/226] doc: west: add 0.11.0 docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is mainly a feature release which includes a few ways to speed up 'west update', along with a couple of fixes and other changes. Signed-off-by: Martí Bolívar --- doc/guides/west/built-in.rst | 26 ++++++++++++++++++++------ doc/guides/west/config.rst | 12 ++++++++++++ doc/guides/west/index.rst | 2 +- doc/guides/west/release-notes.rst | 25 +++++++++++++++++++++++++ doc/guides/west/west-apis.rst | 14 ++++++++++++++ 5 files changed, 72 insertions(+), 7 deletions(-) diff --git a/doc/guides/west/built-in.rst b/doc/guides/west/built-in.rst index 04ef48ac..c84dc986 100644 --- a/doc/guides/west/built-in.rst +++ b/doc/guides/west/built-in.rst @@ -197,9 +197,15 @@ if you just want to disable a single group, e.g. ``--group-filter=-bar``. If a project in the manifest has a ``submodules`` key, the submodules are updated as follows, depending on the value of the ``submodules`` key. -If the project has ``submodules: true``, west runs one of the following in -the project repository, depending on whether you run ``west update`` -with the ``--rebase`` option or without it: +If the project has ``submodules: true``, west first synchronizes the project's +submodules with: + +.. code-block:: + + git submodule sync --recursive + +West then runs one of the following in the project repository, depending on +whether you run ``west update`` with the ``--rebase`` option or without it: .. code-block:: @@ -210,9 +216,14 @@ with the ``--rebase`` option or without it: git submodule update --init --rebase --recursive Otherwise, the project has ``submodules: ``. In this -case, west runs one of the following in the project repository for each -submodule path in the list, depending on whether you run ``west update`` -with the ``--rebase`` option or without it: +case, west synchronizes the project's submodules with: + +.. code-block:: + + git submodule sync --recursive -- + +Then it updates each submodule in the list as follows, depending on whether you +run ``west update`` with the ``--rebase`` option or without it: .. code-block:: @@ -222,6 +233,9 @@ with the ``--rebase`` option or without it: # with --rebase, e.g. "west update --rebase": git submodule update --init --rebase --recursive +The ``git submodule sync`` commands are skipped if the +``update.sync-submodules`` :ref:`west-config` option is false. + .. _west-built-in-misc: Other project commands diff --git a/doc/guides/west/config.rst b/doc/guides/west/config.rst index d1e2f660..93951ad5 100644 --- a/doc/guides/west/config.rst +++ b/doc/guides/west/config.rst @@ -156,6 +156,18 @@ commands are documented in the pages for those commands. from project remotes when those projects' revisions in the manifest file are SHAs or tags which are already available locally. The ``"always"`` behavior is to unconditionally fetch from the remote. + * - ``update.name-cache`` + - String. If non-empty, ``west update`` will use its value as the + ``--name-cache`` option's value if not given on the command line. + * - ``update.narrow`` + - Boolean. If ``true``, ``west update`` behaves as if ``--narrow`` was + given on the command line. The default is ``false``. + * - ``update.path-cache`` + - String. If non-empty, ``west update`` will use its value as the + ``--path-cache`` option's value if not given on the command line. + * - ``update.sync-submodules`` + - Boolean. If ``true`` (the default), :ref:`west-update` will synchronize + Git submodules before updating them. * - ``zephyr.base`` - String, default value to set for the :envvar:`ZEPHYR_BASE` environment variable while the west command is running. By default, this is set to diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 85f1c05b..daab8779 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -26,7 +26,7 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.9.x`` releases, and provide additional +The following pages document west's ``v0.11.x`` releases, and provide additional context about the tool. .. toctree:: diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 65ae43d2..8c033d92 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,6 +1,31 @@ West Release Notes ################## +v0.11.0 +******* + +New features: + +- ``west update`` now supports ``--narrow``, ``--name-cache``, and + ``--path-cache`` options. These can be influenced by the ``update.narrow``, + ``update.name-cache``, and ``update.path-cache`` :ref:`west-config` options. + These can be used to optimize the speed of the update. +- ``west update`` now supports a ``--fetch-opt`` option that will be passed to + the ``git fetch`` command used to fetch remote revisions when updating each + project. + +Bug fixes: + +- ``west update`` now synchronizes Git submodules in projects by default. This + avoids issues if the URL changes in the manifest file from when the submodule + was first initialized. This behavior can be disabled by setting the + ``update.sync-submodules`` configuration option to ``false``. + +Other changes: + +- the :ref:`west-apis-manifest` module has fixed docstrings for the Project + class + v0.10.1 ******* diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 43b3bc29..0ce468c8 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -89,6 +89,12 @@ WestCommand True if reading the manifest property will succeed instead of erroring out. + .. py:attribute:: git_version_info + + A tuple of Git version information. + + .. versionadded:: 0.11.0 + Constructor: .. automethod:: __init__ @@ -109,6 +115,14 @@ WestCommand .. automethod:: add_parser + .. automethod:: check_call + + .. versionchanged:: 0.11.0 + + .. automethod:: check_output + + .. versionchanged:: 0.11.0 + All subclasses must provide the following abstract methods, which are used to implement the above: From 85a6f027fab23ae39b9584bcb71710c2c38b6051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 27 May 2021 10:09:24 -0700 Subject: [PATCH 116/226] doc: add docs for west spdx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are based on the commit log in fd31b9b4acb5d48f83ef8cf0f3afe3e48b7844c0. Signed-off-by: Martí Bolívar --- doc/guides/west/zephyr-cmds.rst | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/doc/guides/west/zephyr-cmds.rst b/doc/guides/west/zephyr-cmds.rst index 83a0849e..ebc3f16c 100644 --- a/doc/guides/west/zephyr-cmds.rst +++ b/doc/guides/west/zephyr-cmds.rst @@ -50,3 +50,76 @@ able to find the Zephyr repository with the following: find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) See :zephyr_file:`share/zephyr-package/cmake` for details. + +.. _west-spdx: + +Software bill of materials: ``west spdx`` +***************************************** + +This command generates SPDX 2.2 tag-value documents, creating relationships +from source files to the corresponding generated build files. +``SPDX-License-Identifier`` comments in source files are scanned and filled +into the SPDX documents. + +To use this command: + +#. Pre-populate a build directory :file:`BUILD_DIR` like this: + + .. code-block:: bash + + west spdx --init -d BUILD_DIR + + This step ensures the build directory contains CMake metadata required for + SPDX document generation. + +#. Build your application using this pre-created build directory, like so: + + .. code-block:: bash + + west build -d BUILD_DIR [...] + +#. Generate SPDX documents using this build directory: + + .. code-block:: bash + + west spdx -d BUILD_DIR + +This generates the following SPDX bill-of-materials (BOM) documents in +:file:`BUILD_DIR/spdx/`: + +- :file:`app.spdx`: BOM for the application source files used for the build +- :file:`zephyr.spdx`: BOM for the specific Zephyr source code files used for + the build +- :file:`build.spdx`: BOM for the built output files + +Each file in the bill-of-materials is scanned, so that its hashes (SHA256 and +SHA1) can be recorded, along with any detected licenses if an +``SPDX-License-Identifier`` comment appears in the file. + +SPDX Relationships are created to indicate dependencies between +CMake build targets, build targets that are linked together, and +source files that are compiled to generate the built library files. + +``west spdx`` accepts these additional options: + +- ``-n PREFIX``: a prefix for the Document Namespaces that will be included in + the generated SPDX documents. See `SPDX specification 2.2 section 2.5`_ for + details. If ``-n`` is omitted, a default namespace will be generated + according to the default format described in section 2.5 using a random UUID. + +- ``-s SPDX_DIR``: specifies an alternate directory where the SPDX documents + should be written instead of :file:`BUILD_DIR/spdx/`. + +- ``--analyze-includes``: in addition to recording the compiled source code + files (e.g. ``.c``, ``.S``) in the bills-of-materials, also attempt to + determine the specific header files that are included for each ``.c`` file. + + This takes longer, as it performs a dry run using the C compiler for each + ``.c`` file using the same arguments that were passed to it for the actual + build. + +- ``--include-sdk``: with ``--analyze-includes``, also create a fourth SPDX + document, :file:`sdk.spdx`, which lists header files included from the SDK. + +.. _SPDX specification 2.2 section 2.5: + https://spdx.github.io/spdx-spec/2-document-creation-information/ From 4871c7cab773784f3329541697e008383a28077c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 27 May 2021 10:09:50 -0700 Subject: [PATCH 117/226] doc: release-notes-2.6: west extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just the extensions changes for Zephyr 2.6, since west has its own release notes page as it's developed on its own pace. Signed-off-by: Martí Bolívar --- doc/guides/west/release-notes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 8c033d92..584f0ee2 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -1,3 +1,5 @@ +.. _west-release-notes: + West Release Notes ################## From d02dbe5b70fafa60eaf09b6bc1fe12fc6dd9d463 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 28 Jun 2021 16:24:59 +0200 Subject: [PATCH 118/226] doc: use kconfig role and directive Stop using :option: for Kconfig options. Signed-off-by: Gerard Marull-Paretas --- doc/guides/west/sign.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/sign.rst b/doc/guides/west/sign.rst index a386d0f4..bc1b7c7f 100644 --- a/doc/guides/west/sign.rst +++ b/doc/guides/west/sign.rst @@ -44,13 +44,13 @@ Notes on the above commands: For more information on these and other related configuration options, see: -- :option:`CONFIG_BOOTLOADER_MCUBOOT`: build the application for loading by +- :kconfig:`CONFIG_BOOTLOADER_MCUBOOT`: build the application for loading by MCUboot -- :option:`CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`: the key file to use with ``west +- :kconfig:`CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`: the key file to use with ``west sign``. If you have your own key, change this appropriately -- :option:`CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS`: optional additional command line +- :kconfig:`CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS`: optional additional command line arguments for ``imgtool`` -- :option:`CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE`: also generate a confirmed +- :kconfig:`CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE`: also generate a confirmed image, which may be more useful for flashing in production environments than the OTA-able default image - On Windows, if you get "Access denied" issues, the recommended fix is From 8680047f0ba1e022e4eaf2ea623a384e9279681a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 30 Jul 2021 13:24:59 -0700 Subject: [PATCH 119/226] doc: west build: examples for -o and how to use -jN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the -o option and use that to explain how to control build system parallelism. Signed-off-by: Martí Bolívar --- doc/guides/west/build-flash-debug.rst | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 079e5a5a..21385a95 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -279,6 +279,38 @@ more details. .. _set() command: https://cmake.org/cmake/help/latest/command/set.html +Build tool arguments +-------------------- + +Use ``-o`` to pass options to the underlying build tool. + +This works with both ``ninja`` (:ref:`the default `) +and ``make`` based build systems. + +For example, to pass ``-dexplain`` to ``ninja``:: + + west build -o=-dexplain + +As another example, to pass ``--keep-going`` to ``make``:: + + west build -o=--keep-going + +Note that using ``-o=--foo`` instead of ``-o --foo`` is required to prevent +``--foo`` from being treated as a ``west build`` option. + +Build parallelism +----------------- + +By default, ``ninja`` uses all of your cores to build, while ``make`` uses only +one. You can control this explicitly with the ``-j`` option supported by both +tools. + +For example, to build with 4 cores:: + + west build -o=-j4 + +The ``-o`` option is described further in the previous section. + .. _west-building-config: Configuration Options From fdb9fd326fac9a002ee67f60cc5a7a7409b28501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 6 Aug 2021 11:13:44 -0700 Subject: [PATCH 120/226] doc: west v0.11.1 notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a stopgap release meant to backport bug fixes and new features while v0.12.0 is blocked. Signed-off-by: Martí Bolívar --- doc/guides/west/manifest.rst | 2 ++ doc/guides/west/release-notes.rst | 53 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 6511a599..557151ee 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -151,6 +151,8 @@ bases are respectively ``https://git.example.com/base1`` and example, you might use ``git@example.com:base1`` if ``remote1`` supported Git over SSH as well. Anything acceptable to Git will work. +.. _west-manifests-projects: + Projects ======== diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 584f0ee2..380eec51 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -3,6 +3,59 @@ West Release Notes ################## +v0.11.1 +******* + +New features: + +- ``west status`` now only prints output for projects which have a nonempty + status. + +Bug fixes: + +- The manifest file parser was incorrectly allowing project names which contain + the path separator characters ``/`` and ``\\``. These invalid characters are + now rejected. + + Note: if you need to place a project within a subdirectory of the workspace + topdir, use the ``path:`` key. If you need to customize a project's fetch URL + relative to its remote ``url-base:``, use ``repo-path:``. See + :ref:`west-manifests-projects` for examples. + +- The changes made in west v0.10.1 to the ``west init --manifest-rev`` option + which selected the default branch name were leaving the manifest repository + in a detached HEAD state. This has been fixed by using ``git clone`` internally + instead of ``git init`` and ``git fetch``. See `issue #522`_ for details. + +- The :envvar:`WEST_CONFIG_LOCAL` environment variable now correctly + overrides the default location, :file:`/.west/config`. + +- ``west update --fetch=smart`` (``smart`` is the default) now correclty skips + fetches for project revisions which are `lightweight tags`_ (it already + worked correctly for annotated tags; only lightweight tags were unnecessarily + fetched). + +Other changes: + +- The fix for issue #522 mentioned above introduces a new restriction. The + ``west init --manifest-rev`` option value, if given, must now be either a + branch or a tag. In particular, "pseudo-branches" like GitHub's + ``pull/1234/head`` references which could previously be used to fetch a pull + request can no longer be passed to ``--manifest-rev``. Users must now fetch + and check out such revisions manually after running ``west init``. + +:ref:`API ` changes: + +- ``west.manifest.Manifest.get_projects()`` avoids incorrect results in + some edge cases described in `issue #523`_. + +- ``west.manifest.Project.sha()`` now works correctly for tag revisions. + (This applies to both lightweight and annotated tags.) + +.. _lightweight tags: https://git-scm.com/book/en/v2/Git-Basics-Tagging +.. _issue #522: https://github.com/zephyrproject-rtos/west/issues/522 +.. _issue #523: https://github.com/zephyrproject-rtos/west/issues/523 + v0.11.0 ******* From 31ccbfa24489217d329593e0185d0c5c74c0ef31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 10 Aug 2021 11:23:56 -0700 Subject: [PATCH 121/226] doc: west release 0.11.1 follow-ups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use 0.11.1 to build the docs. The docstrings are the same as 0.11.1a1, so it doesn't make a difference in the output, but let's keep things clean now that the final release is up. Fix typos in the release notes. Signed-off-by: Martí Bolívar --- doc/guides/west/release-notes.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index 380eec51..c885a993 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -14,7 +14,7 @@ New features: Bug fixes: - The manifest file parser was incorrectly allowing project names which contain - the path separator characters ``/`` and ``\\``. These invalid characters are + the path separator characters ``/`` and ``\``. These invalid characters are now rejected. Note: if you need to place a project within a subdirectory of the workspace @@ -30,7 +30,7 @@ Bug fixes: - The :envvar:`WEST_CONFIG_LOCAL` environment variable now correctly overrides the default location, :file:`/.west/config`. -- ``west update --fetch=smart`` (``smart`` is the default) now correclty skips +- ``west update --fetch=smart`` (``smart`` is the default) now correctly skips fetches for project revisions which are `lightweight tags`_ (it already worked correctly for annotated tags; only lightweight tags were unnecessarily fetched). From 8d3ec5eb8aa338ace2530c5935a56c6b9fcb418e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 4 Nov 2021 06:13:37 -0700 Subject: [PATCH 122/226] doc: west 0.12 docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the documentation for this release. Signed-off-by: Martí Bolívar --- doc/guides/west/index.rst | 2 +- doc/guides/west/manifest.rst | 42 +++++++++++++++++++++++++++++++ doc/guides/west/release-notes.rst | 21 ++++++++++++++++ doc/guides/west/west-apis.rst | 3 +++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index daab8779..91a509f0 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -26,7 +26,7 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.11.x`` releases, and provide additional +The following pages document west's ``v0.12.x`` releases, and provide additional context about the tool. .. toctree:: diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index 557151ee..c82977b8 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -288,6 +288,10 @@ next. submodules`_ defined by the project. See :ref:`west-manifest-submodules` for details. + * - ``userdata`` + - Optional. The value is an arbitrary YAML value. See + :ref:`west-project-userdata`. + .. _Git submodules: https://git-scm.com/book/en/v2/Git-Tools-Submodules Defaults @@ -1054,6 +1058,44 @@ Here, ``west update`` will recursively initialize and update just the submodules in ``foo`` with paths ``path/to/foo-first-sub`` and ``path/to/foo-second-sub``. Any submodules in ``bar`` are still ignored. +.. _west-project-userdata: + +Project user data +***************** + +West versions v0.12 and later support an optional ``userdata`` key in projects. +It is meant for consumption by programs that require user-specific project +metadata. Beyond parsing it as YAML, west itself ignores the value completely. + +The key's value is arbitrary YAML. West parses the value and makes it +accessible to programs using :ref:`west-apis` as the ``userdata`` attribute of +the corresponding ``west.manifest.Project`` object. + +Example manifest fragment: + +.. code-block:: yaml + + manifest: + projects: + - name: foo + - name: bar + userdata: a-string + - name: baz + userdata: + key: value + +Example Python usage: + +.. code-block:: python + + manifest = west.manifest.Manifest.from_file() + + foo, bar, baz = manifest.get_projects(['foo', 'bar', 'baz']) + + foo.userdata # None + bar.userdata # 'a-string' + baz.userdata # {'key': 'value'} + .. _west-manifest-import: Manifest Imports diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index c885a993..ac758747 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -3,6 +3,27 @@ West Release Notes ################## +v0.12.0 +******* + +New features: + +- West now works on the `MSYS2 `_ platform. + +- West manifest files can now contain arbitrary user data associated with each + project. See :ref:`west-project-userdata` for details. + +Bug fixes: + +- The ``west list`` command's ``{sha}`` format key has been fixed for + the manifest repository; it now prints ``N/A`` ("not applicable") + as expected. + +:ref:`API ` changes: + +- The ``west.manifest.Project.userdata`` attribute was added to support + project user data. + v0.11.1 ******* diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 0ce468c8..2a69c610 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -304,6 +304,9 @@ Manifest and sub-objects .. versionadded:: 0.9.0 The *group_filter* and *submodules* attributes. + .. versionadded:: 0.12.0 + The *userdata* attribute. + Constructor: .. automethod:: __init__ From 4d5295d6b6fe8890c197898ca553657306e14175 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 16 Nov 2021 19:17:02 +0100 Subject: [PATCH 123/226] doc: west: build-flash-debug: fix cmake arg example The shorter version of --cmake argument should contain one dash only. Signed-off-by: Bartosz Bilas --- doc/guides/west/build-flash-debug.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/west/build-flash-debug.rst b/doc/guides/west/build-flash-debug.rst index 21385a95..f741b847 100644 --- a/doc/guides/west/build-flash-debug.rst +++ b/doc/guides/west/build-flash-debug.rst @@ -75,7 +75,7 @@ Here are some ``west build`` usage examples, grouped by area. Forcing CMake to Run Again -------------------------- -To force a CMake re-run, use the ``--cmake`` (or ``--c``) option:: +To force a CMake re-run, use the ``--cmake`` (or ``-c``) option:: west build -c From b752a85d889d59f58522a9889f8b07a0191aeab4 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 10 Dec 2021 13:14:27 +0100 Subject: [PATCH 124/226] doc: drop single quote references Many documents relied on single quotes to create references, e.g. `my_reference`. This is possible because `default_role = "any"` is enabled in Sphinx conf.py. However, this method comes with its problems: - It mixes all domains together, so it's not clear to what are you referencing: a document? a Kconfig option? a C function?... - It creates inconsistencies: in some places explicit roles are used (e.g. :ref:`my_page`) while in some others not. - _Conflictis_ with markdown. Single quotes are used for literals in Markdown, so people tend to use the same syntax in Sphinx, even though it has a different purpose. Usages have been found using `git grep ' `[^`]*` ' -- **/*.rst`. Signed-off-by: Gerard Marull-Paretas --- doc/guides/west/west-apis.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 2a69c610..53f444b6 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -226,9 +226,10 @@ west.manifest .. automodule:: west.manifest -The main classes are `Manifest` and `Project`. These represent the contents of -a :ref:`manifest file `. The recommended methods for parsing -west manifests are `Manifest.from_file` and `Manifest.from_data`. +The main classes are :py:class:`Manifest` and :py:class:`Project`. These +represent the contents of a :ref:`manifest file `. The +recommended methods for parsing west manifests are +:py:meth:`Manifest.from_file` and :py:meth:`Manifest.from_data`. Constants and functions ======================= From fb3df61a579a2e1758b8ea1d5d6938377e90f457 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 17 Jan 2022 11:35:05 +0100 Subject: [PATCH 125/226] doc: use extlink for github issue links Use extlink for GitHub issue links in documentation. Signed-off-by: Henrik Brix Andersen --- doc/guides/west/why.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/west/why.rst b/doc/guides/west/why.rst index e1f51381..87220b6b 100644 --- a/doc/guides/west/why.rst +++ b/doc/guides/west/why.rst @@ -120,4 +120,4 @@ West is: See `Zephyr issue #6205`_ and for more details and discussion. .. _Zephyr issue #6205: - https://github.com/zephyrproject-rtos/zephyr/issues/6205 + :github:`6205` From d0ffe718cfe5a669539d7292826bff300afdee7d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 17 Jan 2022 18:01:10 +0100 Subject: [PATCH 126/226] doc: fix PDF build issue due to extlink references LaTeX code generated by Sphinx causes problems when using extlinks in references. Mitigate the problem by just using the extlink role directly. Signed-off-by: Gerard Marull-Paretas --- doc/guides/west/why.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/guides/west/why.rst b/doc/guides/west/why.rst index 87220b6b..628d5575 100644 --- a/doc/guides/west/why.rst +++ b/doc/guides/west/why.rst @@ -117,7 +117,4 @@ West is: interoperability with third party tools, and means Zephyr developers can always find out what is happening "under the hood" when using west. -See `Zephyr issue #6205`_ and for more details and discussion. - -.. _Zephyr issue #6205: - :github:`6205` +See :github:`Zephyr issue #6205 <6205>` and for more details and discussion. From b35b7b665faba2e491b14c00030e27cc6050ee57 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 7 Feb 2022 17:27:43 +0100 Subject: [PATCH 127/226] doc: use :kconfig:option: domain role Kconfig options now belong to the Kconfig domain, therefore, the :kconfig:option: role needs to be used. Signed-off-by: Gerard Marull-Paretas --- doc/guides/west/sign.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/guides/west/sign.rst b/doc/guides/west/sign.rst index bc1b7c7f..93d7406a 100644 --- a/doc/guides/west/sign.rst +++ b/doc/guides/west/sign.rst @@ -44,13 +44,13 @@ Notes on the above commands: For more information on these and other related configuration options, see: -- :kconfig:`CONFIG_BOOTLOADER_MCUBOOT`: build the application for loading by +- :kconfig:option:`CONFIG_BOOTLOADER_MCUBOOT`: build the application for loading by MCUboot -- :kconfig:`CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`: the key file to use with ``west +- :kconfig:option:`CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`: the key file to use with ``west sign``. If you have your own key, change this appropriately -- :kconfig:`CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS`: optional additional command line +- :kconfig:option:`CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS`: optional additional command line arguments for ``imgtool`` -- :kconfig:`CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE`: also generate a confirmed +- :kconfig:option:`CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE`: also generate a confirmed image, which may be more useful for flashing in production environments than the OTA-able default image - On Windows, if you get "Access denied" issues, the recommended fix is From 8809ed3fe4706d780cc843a223e565d5829aba6a Mon Sep 17 00:00:00 2001 From: Nazar Kazakov Date: Wed, 16 Mar 2022 21:07:43 +0000 Subject: [PATCH 128/226] everywhere: fix typos Fix a lot of typos Signed-off-by: Nazar Kazakov --- doc/guides/west/extensions.rst | 2 +- doc/guides/west/install.rst | 2 +- doc/guides/west/workspaces.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/guides/west/extensions.rst b/doc/guides/west/extensions.rst index fe4fc8f8..520e0ec4 100644 --- a/doc/guides/west/extensions.rst +++ b/doc/guides/west/extensions.rst @@ -202,7 +202,7 @@ Above: #. ``a-third-command`` with class ``ThirdCommand`` See the file :file:`west-commands-schema.yml` in the `west repository`_ for a -schema describing the contents of a :file:`west-comands.yml`. +schema describing the contents of a :file:`west-commands.yml`. Step 3: Update Your Manifest ============================ diff --git a/doc/guides/west/install.rst b/doc/guides/west/install.rst index 5734ee83..e9f877cb 100644 --- a/doc/guides/west/install.rst +++ b/doc/guides/west/install.rst @@ -36,7 +36,7 @@ This distribution includes a launcher executable, which is also named When west is installed, the launcher is placed by :file:`pip3` somewhere in the user's filesystem (exactly where depends on the operating system, but should be on the ``PATH`` :ref:`environment variable `). This -launcher is the command-line entry point to running both built-in commmands +launcher is the command-line entry point to running both built-in commands like ``west init``, ``west update``, along with any extensions discovered in the workspace. diff --git a/doc/guides/west/workspaces.rst b/doc/guides/west/workspaces.rst index f581d5e4..a46d46d8 100644 --- a/doc/guides/west/workspaces.rst +++ b/doc/guides/west/workspaces.rst @@ -93,7 +93,7 @@ To use this helper by default on your computer, run: On GitHub, you can set up a `personal access token`_ to use in place of your account password. (This may be required if your account has two-factor authentication enabled, and may be preferable to storing your account password -in plain text even if two-factor authentication is disabed.) +in plain text even if two-factor authentication is disabled.) If you don't want to store any credentials on the file system, you can store them in memory temporarily using `git-credential-cache`_ instead. From 6fba9469ea96b6a6a55b6a21ebeefff4c2368656 Mon Sep 17 00:00:00 2001 From: Steve Winslow Date: Sat, 19 Mar 2022 15:11:59 -0400 Subject: [PATCH 129/226] doc: Fix west spdx command docs formatting bug Fixes #43993 Signed-off-by: Steve Winslow --- doc/guides/west/zephyr-cmds.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/guides/west/zephyr-cmds.rst b/doc/guides/west/zephyr-cmds.rst index ebc3f16c..2e59c378 100644 --- a/doc/guides/west/zephyr-cmds.rst +++ b/doc/guides/west/zephyr-cmds.rst @@ -88,8 +88,7 @@ This generates the following SPDX bill-of-materials (BOM) documents in :file:`BUILD_DIR/spdx/`: - :file:`app.spdx`: BOM for the application source files used for the build -- :file:`zephyr.spdx`: BOM for the specific Zephyr source code files used for - the build +- :file:`zephyr.spdx`: BOM for the specific Zephyr source code files used for the build - :file:`build.spdx`: BOM for the built output files Each file in the bill-of-materials is scanned, so that its hashes (SHA256 and From a955e3782382a389dc9aa082ecdcb31512df771e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 22 Mar 2022 17:15:48 +0200 Subject: [PATCH 130/226] doc: west: Add mention about Git rewrite feature Add Git rewrite feature mention, which can simplify handling of HTTPS URLs. Signed-off-by: Andrei Emeltchenko --- doc/guides/west/workspaces.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/guides/west/workspaces.rst b/doc/guides/west/workspaces.rst index a46d46d8..dfee896d 100644 --- a/doc/guides/west/workspaces.rst +++ b/doc/guides/west/workspaces.rst @@ -98,6 +98,13 @@ in plain text even if two-factor authentication is disabled.) If you don't want to store any credentials on the file system, you can store them in memory temporarily using `git-credential-cache`_ instead. +If you setup fetching via SSH, you can use Git URL rewrite feature. The following +command instructs Git to use SSH URLs for GitHub instead of HTTPS ones: + +.. code-block:: shell + + git config --global url."git@github.com:".insteadOf "https://github.com/" + .. _git-credential-store: https://git-scm.com/docs/git-credential-store#_examples .. _git-credential-cache: From 60f8b8f8397bc58472c0a8866272180f8bcc0b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 4 Apr 2022 14:35:32 -0700 Subject: [PATCH 131/226] doc: west: v0.13.0 docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the release notes and update the documentation. Signed-off-by: Martí Bolívar --- doc/guides/west/index.rst | 2 +- doc/guides/west/manifest.rst | 19 +++++-- doc/guides/west/release-notes.rst | 74 +++++++++++++++++++++++++ doc/guides/west/west-apis.rst | 86 +++++++++++++++++++++++++----- doc/guides/west/west-not-found.rst | 1 + 5 files changed, 164 insertions(+), 18 deletions(-) diff --git a/doc/guides/west/index.rst b/doc/guides/west/index.rst index 91a509f0..3f2d9bc1 100644 --- a/doc/guides/west/index.rst +++ b/doc/guides/west/index.rst @@ -26,7 +26,7 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.12.x`` releases, and provide additional +The following pages document west's ``v0.13.x`` releases, and provide additional context about the tool. .. toctree:: diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst index c82977b8..8b7cae10 100644 --- a/doc/guides/west/manifest.rst +++ b/doc/guides/west/manifest.rst @@ -410,9 +410,13 @@ manifest file schema that can parse this file's data: The pykwalify schema :file:`manifest-schema.yml` in the west source code repository is used to validate the manifest section. The current manifest -``version`` is 0.10, which is supported by west version v0.10.x. +``version`` is 0.13, which is supported by west version v0.13.x. + +The ``version`` value may be any one of these values: ``"0.7"``, ``"0.8"``, +``"0.9"``, ``"0.10"``, ``"0.12"``, ``"0.13"``. West v0.11 did not include any +new features which broke the previous schema, so ``"0.11"`` **is not** a valid +schema version. -The ``version`` value may be ``"0.7"``, ``"0.8"``, ``"0.9"``, or ``"0.10"``. West v0.10.x can load manifests with any of these ``version`` values, while west v0.9.x can only load versions up to ``"0.9"``, and so on. @@ -1060,10 +1064,14 @@ submodules in ``foo`` with paths ``path/to/foo-first-sub`` and .. _west-project-userdata: -Project user data -***************** +Repository user data +******************** West versions v0.12 and later support an optional ``userdata`` key in projects. + +West versions v0.13 and later supports this key in the ``manifest: self:`` +section. + It is meant for consumption by programs that require user-specific project metadata. Beyond parsing it as YAML, west itself ignores the value completely. @@ -1083,6 +1091,8 @@ Example manifest fragment: - name: baz userdata: key: value + self: + userdata: blub Example Python usage: @@ -1095,6 +1105,7 @@ Example Python usage: foo.userdata # None bar.userdata # 'a-string' baz.userdata # {'key': 'value'} + manifest.userdata # 'blub' .. _west-manifest-import: diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst index ac758747..fc406605 100644 --- a/doc/guides/west/release-notes.rst +++ b/doc/guides/west/release-notes.rst @@ -3,6 +3,80 @@ West Release Notes ################## +v0.13.0 +******* + +New features: + +- You can now associate arbitrary user data with the manifest repository + itself in the ``manifest: self: userdata:`` value, like so: + + .. code-block:: YAML + + manifest: + self: + userdata: + +Bug fixes: + +- The path to the manifest repository reported by west could be incorrect in + certain circumstances detailed in [issue + #572](https://github.com/zephyrproject-rtos/west/issues/572). This has been + fixed as part of a larger overhaul of path handling support in the + ``west.manifest`` API module. + +- The ``west.Manifest.ManifestProject.__repr__`` return value was fixed + +:ref:`API ` changes: + +- ``west.configuration.Configuration``: new object-oriented interface to the + current configuration. This reflects the system, global, and workspace-local + configuration values, and allows you to read, write, and delete configuration + options from any or all of these locations. + +- ``west.commands.WestCommand``: + + - ``config``: new attribute, returns a ``Configuration`` object or aborts the + program if none is set. This is always usable from within extension command + ``do_run()`` implementations. + - ``has_config``: new boolean attribute, which is ``True`` if and only if + reading ``self.config`` will abort the program. + +- The path handling in the ``west.manifest`` package has been overhauled in a + backwards-incompatible way. For more details, see commit + [56cfe8d1d1](https://github.com/zephyrproject-rtos/west/commit/56cfe8d1d1f3c9b45de3e793c738acd62db52aca). + +- ``west.manifest.Manifest.validate()``: this now returns the validated data as + a Python dict. This can be useful if the value passed to this function was a + str, and the dict is desired. + +- ``west.manifest.Manifest``: new: + + - path attributes ``abspath``, ``posixpath``, ``relative_path``, + ``yaml_path``, ``repo_path``, ``repo_posixpath`` + - ``userdata`` attribute, which contains the parsed value + from ``manifest: self: userdata:``, or is None + - ``from_topdir()`` factory method + +- ``west.manifest.ManifestProject``: new ``userdata`` attribute, which also + contains the parsed value from ``manifest: self: userdata:``, or is None + +- ``west.manifest.ManifestImportFailed``: the constructor can now take any + value; this can be used to reflect failed imports from a :ref:`map + ` or other compound value. + +- Deprecated configuration APIs: + + The following APIs are now deprecated in favor of using a ``Configuration`` + object. Usually this will be done via ``self.config`` from a ``WestCommand`` + instance, but this can be done directly by instantiating a ``Configuration`` + object for other usages. + + - ``west.configuration.config`` + - ``west.configuration.read_config`` + - ``west.configuration.update_config`` + - ``west.configuration.delete_config`` + v0.12.0 ******* diff --git a/doc/guides/west/west-apis.rst b/doc/guides/west/west-apis.rst index 53f444b6..e56dc54f 100644 --- a/doc/guides/west/west-apis.rst +++ b/doc/guides/west/west-apis.rst @@ -89,6 +89,22 @@ WestCommand True if reading the manifest property will succeed instead of erroring out. + .. py:attribute:: config + + A settable property which returns the + :py:class:`west.configuration.Configuration` instance or aborts the + program if one was not provided. This is only safe to use from the + ``do_run()`` method. + + .. versionadded:: 0.13.0 + + .. py:attribute:: has_config + + True if reading the config property will succeed instead of erroring + out. + + .. versionadded:: 0.13.0 + .. py:attribute:: git_version_info A tuple of Git version information. @@ -99,12 +115,14 @@ WestCommand .. automethod:: __init__ - .. versionchanged:: 0.8.0 - The *topdir* parameter can now be any ``os.PathLike``. .. versionadded:: 0.6.0 - The *requires_installation* parameter. + The *requires_installation* parameter (removed in v0.13.0). .. versionadded:: 0.7.0 The *requires_workspace* parameter. + .. versionchanged:: 0.8.0 + The *topdir* parameter can now be any ``os.PathLike``. + .. versionchanged:: 0.13.0 + The deprecated *requires_installation* parameter was removed. Methods: @@ -150,10 +168,35 @@ west.configuration .. automodule:: west.configuration -This provides API access to west configuration files and data. +Since west v0.13, the recommended class for reading this is +:py:class:`west.configuration.Configuration`. + +Note that if you are writing a :ref:`west extension `, you can +access the current ``Configuration`` object as ``self.configuration``. See +:py:class:`west.commands.WestCommand`. -Reading and writing options -=========================== +Configuration API +================= + +This is the recommended API to use since west v0.13. + +.. autoclass:: west.configuration.ConfigFile + +.. autoclass:: west.configuration.Configuration + :members: + + .. versionadded:: 0.13.0 + +Deprecated APIs +=============== + +The following APIs also use :py:class:`west.configuration.ConfigFile`, but they +operate by default on a global object which stores the current workspace +configuration. This has proven to be a bad design descision since west's APIs +can be used from multiple workspaces. They were deprecated in west v0.13.0. + +These APIs are preserved for compatibility with older extensions. They should +not be used in new code when west v0.13.0 or later may be assumed. .. autofunction:: west.configuration.read_config @@ -165,11 +208,6 @@ Reading and writing options .. autofunction:: west.configuration.update_config -.. autoclass:: west.configuration.ConfigFile - -Global configuration instance -============================= - .. py:data:: west.configuration.config Module-global ConfigParser instance for the current configuration. This @@ -244,6 +282,9 @@ Constants and functions .. autofunction:: west.manifest.validate +.. versionchanged:: 0.13.0 + This returns the validated dict containing the parsed YAML data. + Manifest and sub-objects ======================== @@ -252,17 +293,33 @@ Manifest and sub-objects .. automethod:: __init__ .. versionchanged:: 0.7.0 The *importer* and *import_flags* keyword arguments. + .. versionchanged:: 0.13.0 + All arguments were made keyword-only. The *source_file* argument was + removed (use *topdir* instead). The function no longer raises + ``WestNotFound``. + .. versionadded:: 0.13.0 + The *config* argument. + .. versionadded:: 0.13.0 + The *abspath*, *posixpath*, *relative_path*, *yaml_path*, *repo_path*, + *repo_posixpath*, and *userdata* attributes. + + .. automethod:: from_topdir + .. versionadded:: 0.13.0 .. automethod:: from_file + .. versionchanged:: 0.7.0 + ``**kwargs`` added. .. versionchanged:: 0.8.0 The *source_file*, *manifest_path*, and *topdir* arguments can now be any ``os.PathLike``. - .. versionchanged:: 0.7.0 - ``**kwargs`` added. + .. versionchanged:: 0.13.0 + The *manifest_path* and *topdir* arguments were removed. .. automethod:: from_data .. versionchanged:: 0.7.0 ``**kwargs`` added, and *source_data* may be a ``str``. + .. versionchanged:: 0.13.0 + The *manifest_path* and *topdir* arguments were removed. Conveniences for accessing sub-objects by name or other identifier: @@ -400,6 +457,9 @@ Exceptions .. versionchanged:: 0.8.0 The *filename* argument can now be any ``os.PathLike``. + .. versionchanged:: 0.13.0 + The *filename* argument was renamed *imp*, and can now take any value. + .. _west-apis-util: west.util diff --git a/doc/guides/west/west-not-found.rst b/doc/guides/west/west-not-found.rst index 76cc6d79..27f48e3d 100644 --- a/doc/guides/west/west-not-found.rst +++ b/doc/guides/west/west-not-found.rst @@ -3,6 +3,7 @@ .. _west-apis: .. _west-apis-west: .. _west-apis-commands: +.. _west-apis-westcommand: .. _west-apis-configuration: .. _west-apis-log: .. _west-apis-manifest: From 7479c5abf3d5197518b919b0727f398ea899c851 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 5 Apr 2022 08:47:52 -0400 Subject: [PATCH 132/226] doc: move west section to developing with zephyr Move all west docs into the new `developing with zephyr` section. Signed-off-by: Anas Nashif --- doc/{guides => develop}/west/basics.rst | 0 doc/{guides => develop}/west/build-flash-debug.rst | 0 doc/{guides => develop}/west/built-in.rst | 0 doc/{guides => develop}/west/config.rst | 0 doc/{guides => develop}/west/extensions.rst | 0 doc/{guides => develop}/west/index.rst | 0 doc/{guides => develop}/west/install.rst | 0 doc/{guides => develop}/west/manifest.rst | 0 doc/{guides => develop}/west/moving-to-west.rst | 0 doc/{guides => develop}/west/release-notes.rst | 0 doc/{guides => develop}/west/sign.rst | 0 doc/{guides => develop}/west/troubleshooting.rst | 0 doc/{guides => develop}/west/west-apis.rst | 0 doc/{guides => develop}/west/west-mr-model.png | Bin doc/{guides => develop}/west/west-not-found.rst | 0 doc/{guides => develop}/west/why.rst | 0 doc/{guides => develop}/west/without-west.rst | 0 doc/{guides => develop}/west/workspaces.rst | 0 doc/{guides => develop}/west/zephyr-cmds.rst | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename doc/{guides => develop}/west/basics.rst (100%) rename doc/{guides => develop}/west/build-flash-debug.rst (100%) rename doc/{guides => develop}/west/built-in.rst (100%) rename doc/{guides => develop}/west/config.rst (100%) rename doc/{guides => develop}/west/extensions.rst (100%) rename doc/{guides => develop}/west/index.rst (100%) rename doc/{guides => develop}/west/install.rst (100%) rename doc/{guides => develop}/west/manifest.rst (100%) rename doc/{guides => develop}/west/moving-to-west.rst (100%) rename doc/{guides => develop}/west/release-notes.rst (100%) rename doc/{guides => develop}/west/sign.rst (100%) rename doc/{guides => develop}/west/troubleshooting.rst (100%) rename doc/{guides => develop}/west/west-apis.rst (100%) rename doc/{guides => develop}/west/west-mr-model.png (100%) rename doc/{guides => develop}/west/west-not-found.rst (100%) rename doc/{guides => develop}/west/why.rst (100%) rename doc/{guides => develop}/west/without-west.rst (100%) rename doc/{guides => develop}/west/workspaces.rst (100%) rename doc/{guides => develop}/west/zephyr-cmds.rst (100%) diff --git a/doc/guides/west/basics.rst b/doc/develop/west/basics.rst similarity index 100% rename from doc/guides/west/basics.rst rename to doc/develop/west/basics.rst diff --git a/doc/guides/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst similarity index 100% rename from doc/guides/west/build-flash-debug.rst rename to doc/develop/west/build-flash-debug.rst diff --git a/doc/guides/west/built-in.rst b/doc/develop/west/built-in.rst similarity index 100% rename from doc/guides/west/built-in.rst rename to doc/develop/west/built-in.rst diff --git a/doc/guides/west/config.rst b/doc/develop/west/config.rst similarity index 100% rename from doc/guides/west/config.rst rename to doc/develop/west/config.rst diff --git a/doc/guides/west/extensions.rst b/doc/develop/west/extensions.rst similarity index 100% rename from doc/guides/west/extensions.rst rename to doc/develop/west/extensions.rst diff --git a/doc/guides/west/index.rst b/doc/develop/west/index.rst similarity index 100% rename from doc/guides/west/index.rst rename to doc/develop/west/index.rst diff --git a/doc/guides/west/install.rst b/doc/develop/west/install.rst similarity index 100% rename from doc/guides/west/install.rst rename to doc/develop/west/install.rst diff --git a/doc/guides/west/manifest.rst b/doc/develop/west/manifest.rst similarity index 100% rename from doc/guides/west/manifest.rst rename to doc/develop/west/manifest.rst diff --git a/doc/guides/west/moving-to-west.rst b/doc/develop/west/moving-to-west.rst similarity index 100% rename from doc/guides/west/moving-to-west.rst rename to doc/develop/west/moving-to-west.rst diff --git a/doc/guides/west/release-notes.rst b/doc/develop/west/release-notes.rst similarity index 100% rename from doc/guides/west/release-notes.rst rename to doc/develop/west/release-notes.rst diff --git a/doc/guides/west/sign.rst b/doc/develop/west/sign.rst similarity index 100% rename from doc/guides/west/sign.rst rename to doc/develop/west/sign.rst diff --git a/doc/guides/west/troubleshooting.rst b/doc/develop/west/troubleshooting.rst similarity index 100% rename from doc/guides/west/troubleshooting.rst rename to doc/develop/west/troubleshooting.rst diff --git a/doc/guides/west/west-apis.rst b/doc/develop/west/west-apis.rst similarity index 100% rename from doc/guides/west/west-apis.rst rename to doc/develop/west/west-apis.rst diff --git a/doc/guides/west/west-mr-model.png b/doc/develop/west/west-mr-model.png similarity index 100% rename from doc/guides/west/west-mr-model.png rename to doc/develop/west/west-mr-model.png diff --git a/doc/guides/west/west-not-found.rst b/doc/develop/west/west-not-found.rst similarity index 100% rename from doc/guides/west/west-not-found.rst rename to doc/develop/west/west-not-found.rst diff --git a/doc/guides/west/why.rst b/doc/develop/west/why.rst similarity index 100% rename from doc/guides/west/why.rst rename to doc/develop/west/why.rst diff --git a/doc/guides/west/without-west.rst b/doc/develop/west/without-west.rst similarity index 100% rename from doc/guides/west/without-west.rst rename to doc/develop/west/without-west.rst diff --git a/doc/guides/west/workspaces.rst b/doc/develop/west/workspaces.rst similarity index 100% rename from doc/guides/west/workspaces.rst rename to doc/develop/west/workspaces.rst diff --git a/doc/guides/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst similarity index 100% rename from doc/guides/west/zephyr-cmds.rst rename to doc/develop/west/zephyr-cmds.rst From b62fd2e82a89d573ac3d849908692861d7398849 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Wed, 13 Apr 2022 09:48:18 +0200 Subject: [PATCH 133/226] doc: Fix spelling errors in .rst files Fix spelling errors in assorted .rst files. The errors were found using a tool called 'codespell'. Signed-off-by: Aleksandar Markovic --- doc/develop/west/west-apis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index e56dc54f..08ecb48d 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -192,7 +192,7 @@ Deprecated APIs The following APIs also use :py:class:`west.configuration.ConfigFile`, but they operate by default on a global object which stores the current workspace -configuration. This has proven to be a bad design descision since west's APIs +configuration. This has proven to be a bad design decision since west's APIs can be used from multiple workspaces. They were deprecated in west v0.13.0. These APIs are preserved for compatibility with older extensions. They should From f972812410c009b7355e6d9b4f76ca373ceb82fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 20 Apr 2022 09:53:03 -0700 Subject: [PATCH 134/226] doc: west 0.13.1 release notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a bug fix point release. Signed-off-by: Martí Bolívar --- doc/develop/west/release-notes.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index fc406605..75b6834b 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -3,6 +3,15 @@ West Release Notes ################## +v0.13.1 +******* + +Bug fix: + +- When calling west.manifest.Manifest.from_file() when outside of a + workspace, west again falls back on the ZEPHYR_BASE environment + variable to locate the workspace. + v0.13.0 ******* From 889295efb8d8b792451c0070a863c7d6b95d6790 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 26 Apr 2022 16:41:49 +0200 Subject: [PATCH 135/226] doc: west: Add an example of using the credential store for GitHub A simple one-liner to help users authenticate with GitHub using its Personal Access Token and the Git credential store. Signed-off-by: Carles Cufi --- doc/develop/west/workspaces.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/develop/west/workspaces.rst b/doc/develop/west/workspaces.rst index dfee896d..fe92618f 100644 --- a/doc/develop/west/workspaces.rst +++ b/doc/develop/west/workspaces.rst @@ -95,6 +95,13 @@ account password. (This may be required if your account has two-factor authentication enabled, and may be preferable to storing your account password in plain text even if two-factor authentication is disabled.) +You can use the Git credential store to authenticate with a GitHub PAT +(Personal Access Token) like so: + +.. code-block:: shell + + echo "https://x-access-token:$GH_TOKEN@github.com" >> ~/.git-credentials + If you don't want to store any credentials on the file system, you can store them in memory temporarily using `git-credential-cache`_ instead. From 80f4b61574b145dba868cabee54f3b8c9a1c620e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 9 Jul 2022 22:07:17 +0100 Subject: [PATCH 136/226] doc: drop few reference of -s west build flag This has been removed in: 66c6c5147b west: commands: build: Specify source dir without a flag and hidden from the help, drop it from the documents to avoid confusion. Signed-off-by: Fabio Baltieri --- doc/develop/west/sign.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 93d7406a..6a554174 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -26,8 +26,8 @@ from the :file:`zephyrproject` workspace you created in the .. code-block:: console - west build -b YOUR_BOARD -s bootloader/mcuboot/boot/zephyr -d build-mcuboot - west build -b YOUR_BOARD -s zephyr/samples/hello_world -d build-hello-signed -- \ + west build -b YOUR_BOARD bootloader/mcuboot/boot/zephyr -d build-mcuboot + west build -b YOUR_BOARD zephyr/samples/hello_world -d build-hello-signed -- \ -DCONFIG_BOOTLOADER_MCUBOOT=y \ -DCONFIG_MCUBOOT_SIGNATURE_KEY_FILE=\"bootloader/mcuboot/root-rsa-2048.pem\" From 73f6d7b9e9ada793b442432219ebdb2167808c19 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Mon, 14 Mar 2022 23:27:07 +0100 Subject: [PATCH 137/226] doc: sysbuild documentation guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is this initial sysbuild guide on what sysbuild is and how to build a sample using sysbuild. It provides an architectural overview of sysbuild. Descriptions on how to use `west build` or `cmake` + `ninja` to build projects with the sysbuild infrastructure. Flashing is described through the use of `west flash`. Extending sysbuild with additional Zephyr based applications are described, and reference to CMake documentation for including non-Zephyr based applications are provided. Signed-off-by: Torsten Rasmussen Signed-off-by: Martí Bolívar --- doc/develop/west/build-flash-debug.rst | 93 ++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index f741b847..28981770 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -67,6 +67,32 @@ build directory; ``west build`` can figure out the board from the CMake cache. For new builds, the ``--board`` option, :envvar:`BOARD` environment variable, or ``build.board`` configuration option are checked (in that order). +.. _west-multi-domain-builds: + +Sysbuild (multi-domain builds) +============================== + +:ref:`sysbuild` can be used to create a multi-domain build system combining +multiple images for a single or multiple boards. + +Use ``--sysbuild`` to select the :ref:`sysbuild` build infrastructure with +``west build`` to build multiple domains. + +More detailed information regarding the use of sysbuild can be found in the +:ref:`sysbuild` guide. + +.. tip:: + + The ``build.sysbuild`` configuration option can be enabled to tell + ``west build`` to default build using sysbuild. + ``--no-sysbuild`` can be used to disable sysbuild for a specific build. + +``west build`` will build all domains through the top-level build folder of the +domains specified by sysbuild. + +A single domain from a multi-domain project can be built by using ``--domain`` +argument. + Examples ======== @@ -311,6 +337,19 @@ For example, to build with 4 cores:: The ``-o`` option is described further in the previous section. +Build a single domain +--------------------- + +In a multi-domain build with :ref:`hello_world` and `MCUboot`_, you can use +``--domain hello_world`` to only build this domain:: + + west build --sysbuild --domain hello_world + +The ``--domain`` argument can be combined with the ``--target`` argument to +build the specific target for the target, for example:: + + west build --sysbuild --domain hello_world --target help + .. _west-building-config: Configuration Options @@ -374,6 +413,9 @@ You can :ref:`configure ` ``west build`` using these options. directory). - ``always``: Always make the build folder pristine before building, if a build system is present. + * - ``build.sysbuild`` + - Boolean, default ``false``. If ``true``, build application using the + sysbuild infrastructure. .. _west-flashing: @@ -476,6 +518,23 @@ For example, to print usage information about the ``jlink`` runner:: west flash -H -r jlink +.. _west-multi-domain-flashing: + +Multi-domain flashing +===================== + +When a :ref:`west-multi-domain-builds` folder is detected, then ``west flash`` +will flash all domains in the order defined by sysbuild. + +It is possible to flash the image from a single domain in a multi-domain project +by using ``--domain``. + +For example, in a multi-domain build with :ref:`hello_world` and +`MCUboot`_, you can use the ``--domain hello_world`` domain to only flash +only the image from this domain:: + + west flash --domain hello_world + .. _west-debugging: Debugging: ``west debug``, ``west debugserver`` @@ -576,6 +635,38 @@ For example, to print usage information about the ``jlink`` runner:: west debug -H -r jlink +.. _west-multi-domain-debugging: + +Multi-domain debugging +====================== + +``west debug`` can only debug a single domain at a time. When a +:ref:`west-multi-domain-builds` folder is detected, ``west debug`` +will debug the ``default`` domain specified by sysbuild. + +The default domain will be the application given as the source directory. +See the following example:: + + west build --sysbuild path/to/source/directory + +For example, when building ``hello_world`` with `MCUboot`_ using sysbuild, +``hello_world`` becomes the default domain:: + + west build --sysbuild samples/hello_world + +So to debug ``hello_world`` you can do:: + + west debug + +or:: + + west debug --domain hello_world + +If you wish to debug MCUboot, you must explicitly specify MCUboot as the domain +to debug:: + + west debug --domain mcuboot + .. _west-runner: Flash and debug runners @@ -648,3 +739,5 @@ commands do it). .. _CMake Generator: https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html + +.. _MCUboot: https://mcuboot.com/ From d8ae41fafd17803a4dbfad609214618cbce009ec Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 16 Aug 2022 14:59:47 +0200 Subject: [PATCH 138/226] blobs: Document the command and the module integration Extend the existing documentation by documenting the command itself and the format of the module.yml blobs section. Signed-off-by: Carles Cufi --- doc/develop/west/zephyr-cmds.rst | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 2e59c378..907a2b6e 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -122,3 +122,38 @@ source files that are compiled to generate the built library files. .. _SPDX specification 2.2 section 2.5: https://spdx.github.io/spdx-spec/2-document-creation-information/ + +.. _west-blobs: + +Working with binary blobs: ``west blobs`` +***************************************** + +The ``blobs`` command allows users to interact with :ref:`binary blobs +` declared in one or more :ref:`modules ` via their +:ref:`module.yml ` file. + +The ``blobs`` command has three sub-commands, used to list, fetch or clean (i.e. +delete) the binary blobs themselves. + +You can list binary blobs while specifying the format of the output:: + + west blobs list -f '{module}: {type} {path}' + +For the full set of variables available in ``-f/--format`` run +``west blobs -h``. + +Fetching blobs works in a similar manner:: + + west blobs fetch + +Note that, as described in :ref:`the modules section `, +fetched blobs are stored in a :file:`zephyr/blobs/` folder relative to the root +of the corresponding module repository. + +As does deleting them:: + + west blobs clean + +Additionally the tool allows you to specify the modules you want to list, +fetch or clean blobs for by typing the module names as a command-line +parameter. From 3865eca5be50e45702dfc486b05855ea9584c852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 18 Aug 2022 18:34:08 -0700 Subject: [PATCH 139/226] doc: west: mention west blobs in without-west.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This page is out of date now that we have blobs infrastructure managed by west blobs. We need to tell users that they are on their own when it comes to building applications that require blobs if they aren't using west. Signed-off-by: Martí Bolívar --- doc/develop/west/without-west.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/develop/west/without-west.rst b/doc/develop/west/without-west.rst index 5a56aa20..8679e1c8 100644 --- a/doc/develop/west/without-west.rst +++ b/doc/develop/west/without-west.rst @@ -71,6 +71,10 @@ yourself as shown above. See :ref:`modules` for more details. +Similarly, if your application requires binary blobs and you are not using +west, you will need to download and place those blobs in the right places +instead of using ``west blobs``. See :ref:`bin-blobs` for more details. + Flashing and Debugging ---------------------- From 5b60f76fe3a1ca502aa2d0b8ccf4bc3e8f60b220 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 19 Aug 2022 13:30:43 +0200 Subject: [PATCH 140/226] doc: fix incorrect usage of envvar role :envvar: is currently used to tag environment variables, however, :envvar: role expects a matching .. envvar:: directive where the environment variable is defined. This patch fixes some cases by adding envvar directives and by converting certain cases to literals (it doesn't make sense to document all env vars in a list, as some are self-documented by contextual information). Ref. https://www.sphinx-doc.org/en/master/usage/restructuredtext/ roles.html#role-envvar Signed-off-by: Gerard Marull-Paretas --- doc/develop/west/build-flash-debug.rst | 2 +- doc/develop/west/config.rst | 6 +++--- doc/develop/west/release-notes.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 28981770..df8fe921 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -367,7 +367,7 @@ You can :ref:`configure ` ``west build`` using these options. - Description * - ``build.board`` - String. If given, this the board used by :ref:`west build - ` when ``--board`` is not given and :envvar:`BOARD` + ` when ``--board`` is not given and ``BOARD`` is unset in the environment. * - ``build.board_warn`` - Boolean, default ``true``. If ``false``, disables warnings when diff --git a/doc/develop/west/config.rst b/doc/develop/west/config.rst index 93951ad5..35b10de0 100644 --- a/doc/develop/west/config.rst +++ b/doc/develop/west/config.rst @@ -38,11 +38,11 @@ There are three types of configuration file: - All platforms: the default is :file:`.westconfig` in the user's home directory. - - Linux note: if the environment variable :envvar:`XDG_CONFIG_HOME` is set, + - Linux note: if the environment variable ``XDG_CONFIG_HOME`` is set, then :file:`$XDG_CONFIG_HOME/west/config` is used. - Windows note: the following environment variables are tested to find the - home directory: :envvar:`%HOME%`, then :envvar:`%USERPROFILE%`, then a - combination of :envvar:`%HOMEDRIVE%` and :envvar:`%HOMEPATH%`. + home directory: ``%HOME%``, then ``%USERPROFILE%``, then a + combination of ``%HOMEDRIVE%`` and ``%HOMEPATH%``. 3. **Local**: Settings in this file affect west's behavior for the current :term:`west workspace`. The file is :file:`.west/config`, relative diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 75b6834b..9e7aeba6 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -131,7 +131,7 @@ Bug fixes: in a detached HEAD state. This has been fixed by using ``git clone`` internally instead of ``git init`` and ``git fetch``. See `issue #522`_ for details. -- The :envvar:`WEST_CONFIG_LOCAL` environment variable now correctly +- The ``WEST_CONFIG_LOCAL`` environment variable now correctly overrides the default location, :file:`/.west/config`. - ``west update --fetch=smart`` (``smart`` is the default) now correctly skips From affe5539f97d3f1fda2d12873e8641664e394cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 29 Aug 2022 06:48:26 -0700 Subject: [PATCH 141/226] doc: west v0.14 release notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document this bug fix release. Signed-off-by: Martí Bolívar --- doc/develop/west/index.rst | 2 +- doc/develop/west/release-notes.rst | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/doc/develop/west/index.rst b/doc/develop/west/index.rst index 3f2d9bc1..f16053ca 100644 --- a/doc/develop/west/index.rst +++ b/doc/develop/west/index.rst @@ -26,7 +26,7 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.13.x`` releases, and provide additional +The following pages document west's ``v0.14.x`` releases, and provide additional context about the tool. .. toctree:: diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 9e7aeba6..8ab6933b 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -3,6 +3,35 @@ West Release Notes ################## +v0.14.0 +******* + +Bug fixes: + +- West commands that were run with a bad local configuration file dumped stack + in a confusing way. This has been fixed and west now prints a sensible error + message in this case. + +- A bug in the way west looks for the zephyr repository was fixed. The bug + itself usually appeared when running an extension command like ``west build`` + in a new workspace for the first time; this used to fail (just for the first + time, not on subsequent command invocations) unless you ran the command in + the workspace's top level directory. + +- West now prints sensible error messages when the user lacks permission to + open the manifest file instead of dumping stack traces. + +API changes: + +- The ``west.manifest.MalformedConfig`` exception type has been moved to the + ``west.configuration`` module + +- The ``west.manifest.MalformedConfig`` exception type has been moved to the + :ref:`west.configuration ` module + +- The ``west.configuration.Configuration`` class now raises ``MalformedConfig`` + instead of ``RuntimeError`` in some cases + v0.13.1 ******* From deef8a6bf334a5a22431e378d8230ec847c17e2b Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 6 Sep 2022 11:18:25 +0200 Subject: [PATCH 142/226] doc: west: Document the 'west completion' command This extension command was not documented yet, add it to the corresponding page. Signed-off-by: Carles Cufi --- doc/develop/west/zephyr-cmds.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 907a2b6e..ac589e4c 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -27,6 +27,23 @@ Additional help about the formatting options can be found by running:: west boards -h +.. _west-completion: + +Shell completion scripts: ``west completion`` +********************************************* + +The ``completion`` extension command outputs shell completion scripts that can +then be used directly to enable shell completion for the supported shells. + +It currently supports the following shells: + +- bash +- zsh + +Additional instructions are available in the command's help:: + + west help completion + .. _west-zephyr-export: Installing CMake packages: ``west zephyr-export`` From 3c09b24a07ba84e9f2e4e3e4c0e4a6263a1b7adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Fri, 9 Sep 2022 15:27:59 +0200 Subject: [PATCH 143/226] doc: manifest.rst: Describe using 'revision: HEAD~0' in manifests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Describe that using 'HEAD~0' as the revision in manifest files will cause west to not touch that project. Signed-off-by: Øyvind Rønningstad --- doc/develop/west/manifest.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index 8b7cae10..e5518213 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -258,6 +258,9 @@ next. The default ``revision`` is ``master`` if not otherwise specified. + Using ``HEAD~0`` [#f1]_ as the ``revision`` will cause west to keep the current + state of the project. + * - ``path`` - Optional. Relative path specifying where to clone the repository locally, relative to the top directory in the west workspace. If missing, @@ -292,6 +295,16 @@ next. - Optional. The value is an arbitrary YAML value. See :ref:`west-project-userdata`. +.. rubric:: Footnotes + +.. [#f1] In git, HEAD is a reference, whereas HEAD~ is a valid revision but + not a reference. West fetches references, such as refs/heads/main or + HEAD, and commits not available locally, but will not fetch commits if + they are already available. + HEAD~0 is resolved to a specific commit that is locally available, and + therefore west will simply checkout the locally available commit, + identified by HEAD~0. + .. _Git submodules: https://git-scm.com/book/en/v2/Git-Tools-Submodules Defaults From 1b34700cd8da0bc273a40984fe750be9afd2f81d Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Thu, 29 Sep 2022 04:35:10 +0900 Subject: [PATCH 144/226] doc: west: Update outdated link to SPDX specification This commit updates the outdated link to the SPDX specification. Signed-off-by: Stephanos Ioannidis --- doc/develop/west/zephyr-cmds.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index ac589e4c..b0e0bdfd 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -119,7 +119,7 @@ source files that are compiled to generate the built library files. ``west spdx`` accepts these additional options: - ``-n PREFIX``: a prefix for the Document Namespaces that will be included in - the generated SPDX documents. See `SPDX specification 2.2 section 2.5`_ for + the generated SPDX documents. See `SPDX specification clause 6`_ for details. If ``-n`` is omitted, a default namespace will be generated according to the default format described in section 2.5 using a random UUID. @@ -137,8 +137,8 @@ source files that are compiled to generate the built library files. - ``--include-sdk``: with ``--analyze-includes``, also create a fourth SPDX document, :file:`sdk.spdx`, which lists header files included from the SDK. -.. _SPDX specification 2.2 section 2.5: - https://spdx.github.io/spdx-spec/2-document-creation-information/ +.. _SPDX specification clause 6: + https://spdx.github.io/spdx-spec/document-creation-information/ .. _west-blobs: From 25a82d9b4e3dab8c22e35912d6f82c2232a40845 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 9 Jan 2023 15:11:03 +0000 Subject: [PATCH 145/226] tinycbor: Remove deprecated/obsolete module This removes the tinycbor module and replaces references in it e.g. in sample text to use the zcbor replacement. Signed-off-by: Jamie McCrae --- doc/develop/west/basics.rst | 4 ++-- doc/develop/west/workspaces.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/develop/west/basics.rst b/doc/develop/west/basics.rst index 692eef75..6137bf94 100644 --- a/doc/develop/west/basics.rst +++ b/doc/develop/west/basics.rst @@ -29,7 +29,7 @@ workspace looks like this: │ # Projects managed by west: ├── modules/ │ └── lib/ - │ └── tinycbor/ # .git/ project + │ └── zcbor/ # .git/ project ├── net-tools/ # .git/ project └── [ ... other projects ...] @@ -84,7 +84,7 @@ manifest file projects Projects are Git repositories managed by west. Projects are defined in the manifest file and can be located anywhere inside the workspace. In the above - example workspace, ``tinycbor`` and ``net-tools`` are projects. + example workspace, ``zcbor`` and ``net-tools`` are projects. By default, the Zephyr :ref:`build system ` uses west to get the locations of all the projects in the workspace, so any code they contain diff --git a/doc/develop/west/workspaces.rst b/doc/develop/west/workspaces.rst index fe92618f..5c182658 100644 --- a/doc/develop/west/workspaces.rst +++ b/doc/develop/west/workspaces.rst @@ -195,7 +195,7 @@ A workspace using this topology looks like this: │ │ ├── modules/ │   └── lib/ - │   └── tinycbor/ # .git/ project from either the main manifest or some import. + │   └── zcbor/ # .git/ project from either the main manifest or some import. │ └── zephyr/ # .git/ project └── west.yml # This can be partially imported with lower precedence or ignored. @@ -286,7 +286,7 @@ A workspace using this topology looks like this: │   └── west.yml # main manifest with optional import(s) and override(s) ├── modules/ │   └── lib/ - │   └── tinycbor/ # .git/ project from either the main manifest or + │   └── zcbor/ # .git/ project from either the main manifest or │ # from some import │ └── zephyr/ # .git/ project From 072b0b64c13701d280867d950a72c012dba413ca Mon Sep 17 00:00:00 2001 From: Al Semjonovs Date: Mon, 26 Sep 2022 15:39:05 -0600 Subject: [PATCH 146/226] west: Update documentation on twister script integration Adding documentation for twister wrapper west command Signed-off-by: Al Semjonovs --- doc/develop/west/zephyr-cmds.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index b0e0bdfd..7bab6e20 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -174,3 +174,14 @@ As does deleting them:: Additionally the tool allows you to specify the modules you want to list, fetch or clean blobs for by typing the module names as a command-line parameter. + +.. _west-twister: + +Twister wrapper: ``west twister`` +********************************* +This command is a wrapper for :ref:`twister `. + +Twister can then be invoked via west as follows:: + + west twister -help + west twister -T tests/ztest/base From 95605bfc5b8d347938fa8951d3f78e868346b602 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 19 Jan 2023 16:42:41 -0800 Subject: [PATCH 147/226] doc: west: improve 'manifest --validate' section I got a couple of questions about what this command's purpose is and how to debug 'valid' manifests that aren't working as desired. Add some information to address this. Signed-off-by: Marti Bolivar --- doc/develop/west/manifest.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index e5518213..d94e87e8 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -2114,6 +2114,17 @@ or fails with an error: The error message can help diagnose errors. +Here, "invalid" means that the syntax of the manifest file doesn't follow the +rules documented on this page. + +If your manifest is valid but it's not working the way you want it to, turning +up the verbosity with ``-v`` is a good way to get detailed information about +what decisions west made about your manifest, and why: + +.. code-block:: none + + west -v manifest --validate + .. _west-manifest-path: Get the manifest path From 71a6d219eb3e6662603b897f31dec39ca860959d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 17 Feb 2023 15:45:00 -0800 Subject: [PATCH 148/226] doc: west: release notes for west v1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the west v1.0 release, which brings with it stable APIs, removal of legacy APIs, and other changes. Signed-off-by: Martí Bolívar --- doc/develop/west/index.rst | 2 +- doc/develop/west/release-notes.rst | 68 +++++++++++++++++++++++++ doc/develop/west/west-apis.rst | 81 +++++++++++++++++++++++------- 3 files changed, 132 insertions(+), 19 deletions(-) diff --git a/doc/develop/west/index.rst b/doc/develop/west/index.rst index f16053ca..627267fb 100644 --- a/doc/develop/west/index.rst +++ b/doc/develop/west/index.rst @@ -26,7 +26,7 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v0.14.x`` releases, and provide additional +The following pages document west's ``v1.0.y`` releases, and provide additional context about the tool. .. toctree:: diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 8ab6933b..0b49ff3d 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -3,6 +3,74 @@ West Release Notes ################## +v1.0.0 +****** + +Major changes in this release: + +- The :ref:`west-apis` are now declared stable. Any breaking changes will be + communicated by a major version bump from v1.x.y to v2.x.y. + +- West v1.0 no longer works with the Zephyr v1.14 LTS releases. This LTS has + long been obsoleted by Zephyr v2.7 LTS. If you need to use Zephyr v1.14, you + must use west v0.14 or earlier. + +- Like the rest of Zephyr, west now requires Python v3.8 or later + +- West commands no longer accept abbreviated command line arguments. For + example, you must now specify ``west update --keep-descendants`` instead of + using an abbreviation like ``west update --keep-d``. This is part of a change + applied to all of Zephyr's Python scripts' command-line interfaces. The + abbreviations were causing problems in practice when commands were updated to + add new options with similar names but different behavior to existing ones. + +Other changes: + +- All built-in west functions have stopped using ``west.log`` + +- ``west update``: new ``--submodule-init-config`` option. + See commit `9ba92b05`_ for details. + +Bug fixes: + +- West extension commands that failed to load properly sometimes dumped stack. + This has been fixed and west now prints a sensible error message in this case. + +- ``west config`` now fails on malformed configuration option arguments + which lack a ``.`` in the option name + +API changes: + +- The west package now contains the metadata files necessary for some static + analyzers (such as `mypy`_) to auto-detect its type annotations. + See commit `d9f00e24`_ for details. + +- the deprecated ``west.build`` module used for Zephyr v1.14 LTS compatibility was + removed + +- the deprecated ``west.cmake`` module used for Zephyr v1.14 LTS compatibility was + removed + +- the ``west.log`` module is now deprecated. This module's uses global state, + which can make it awkward to use it as an API which multiple different python + modules may rely on. + +- The :ref:`west-apis-commands` module got some new APIs which lay groundwork + for a future change to add a global verbosity control to a command's output, + and work to remove global state from the ``west`` package's API: + + - New ``west.commands.WestCommand.__init__()`` keyword argument: ``verbosity`` + - New ``west.commands.WestCommand`` property: ``color_ui`` + - New ``west.commands.WestCommand`` methods, which should be used to print output + from extension commands instead of writing directly to sys.stdout or + sys.stderr: ``inf()``, ``wrn()``, ``err()``, ``die()``, ``banner()``, + ``small_banner()`` + - New ``west.commands.VERBOSITY`` enum + +.. _9ba92b05: https://github.com/zephyrproject-rtos/west/commit/9ba92b054500d75518ff4c4646590bfe134db523 +.. _d9f00e24: https://github.com/zephyrproject-rtos/west/commit/d9f00e242b8cb297b56e941982adf231281c6bae +.. _mypy: https://www.mypy-lang.org/ + v0.14.0 ******* diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index 08ecb48d..92eb8e7b 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -10,14 +10,6 @@ This page documents the Python APIs provided by :ref:`west `, as well as some additional APIs used by the :ref:`west extensions ` in the zephyr repository. -.. warning:: - - These APIs should be considered unstable until west version 1.0 (see `west - #38`_). - -.. _west #38: - https://github.com/zephyrproject-rtos/west/issues/38 - **Contents**: .. contents:: @@ -111,6 +103,13 @@ WestCommand .. versionadded:: 0.11.0 + .. py:attribute:: color_ui + + True if the west configuration permits colorized output, + False otherwise. + + .. versionadded:: 1.0.0 + Constructor: .. automethod:: __init__ @@ -123,6 +122,8 @@ WestCommand The *topdir* parameter can now be any ``os.PathLike``. .. versionchanged:: 0.13.0 The deprecated *requires_installation* parameter was removed. + .. versionadded:: 1.0.0 + The *verbosity* parameter. Methods: @@ -133,6 +134,9 @@ WestCommand .. automethod:: add_parser + .. automethod:: add_pre_run_hook + .. versionadded:: 1.0.0 + .. automethod:: check_call .. versionchanged:: 0.11.0 @@ -148,6 +152,53 @@ WestCommand .. automethod:: do_run + The following methods should be used when the command needs to print output. + These were introduced to enable a transition from the deprecated + ``west.log`` module to a per-command interface that will allow for a global + "quiet" mode for west commands in a future release: + + .. automethod:: dbg + .. versionadded:: 1.0.0 + + .. automethod:: inf + .. versionadded:: 1.0.0 + + .. automethod:: wrn + .. versionadded:: 1.0.0 + + .. automethod:: err + .. versionadded:: 1.0.0 + + .. automethod:: die + .. versionadded:: 1.0.0 + + .. automethod:: banner + .. versionadded:: 1.0.0 + + .. automethod:: small_banner + .. versionadded:: 1.0.0 + +.. _west-apis-commands-output: + +Verbosity +========= + +Since west v1.0, west commands should print output using methods like +west.commands.WestCommand.dbg(), west.commands.WestCommand.inf(), etc. (see +above). This section documents a related enum used to declare verbosity levels. + +.. autoclass:: west.commands.Verbosity + + .. autoattribute:: QUIET + .. autoattribute:: ERR + .. autoattribute:: WRN + .. autoattribute:: INF + .. autoattribute:: DBG + .. autoattribute:: DBG_MORE + .. autoattribute:: DBG_EXTREME + +.. versionadded:: 1.0.0 + Exceptions ========== @@ -216,17 +267,11 @@ not be used in new code when west v0.13.0 or later may be assumed. .. _west-apis-log: -west.log -******** +west.log (deprecated) +********************* .. automodule:: west.log -This module's functions are used whenever a running west command needs to print -to standard out or error streams. - -This is safe to use from extension commands if you want output that mirrors -that of west itself. - Verbosity control ================= @@ -266,8 +311,8 @@ west.manifest The main classes are :py:class:`Manifest` and :py:class:`Project`. These represent the contents of a :ref:`manifest file `. The -recommended methods for parsing west manifests are -:py:meth:`Manifest.from_file` and :py:meth:`Manifest.from_data`. +recommended method for parsing west manifests is +:py:meth:`Manifest.from_topdir`. Constants and functions ======================= From 89b7c1aec8c73d87cd9101ff25a7834b83720f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Mon, 20 Feb 2023 13:10:33 -0800 Subject: [PATCH 149/226] .github: doc-build: move to west 1.0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The release notes are in and west==1.0.0 is installable via pypi. Move the doc build over to it and fix a typo while we are here. Signed-off-by: Martí Bolívar --- doc/develop/west/release-notes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 0b49ff3d..c4d9d161 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -51,7 +51,7 @@ API changes: - the deprecated ``west.cmake`` module used for Zephyr v1.14 LTS compatibility was removed -- the ``west.log`` module is now deprecated. This module's uses global state, +- the ``west.log`` module is now deprecated. This module uses global state, which can make it awkward to use it as an API which multiple different python modules may rely on. From 9781147a447f3f6305fcf938a6a7dbb02713052c Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Sun, 12 Mar 2023 00:54:25 +0000 Subject: [PATCH 150/226] doc: west: fix WestCommand self.configuration -> self.config WestCommand has no .configuration field, it's .config. In the same (and cursed!) sentence, also fix the broken link to west.command.WestCommand by switching the link target from the unusual `py:class::` to the common `autoclass::` used by all other classes in the same page. I don't understand why that fixes the hyperlink but it works and it's consistent. Signed-off-by: Marc Herbert --- doc/develop/west/west-apis.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index 92eb8e7b..e3e7e393 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -34,7 +34,7 @@ provided. WestCommand =========== -.. py:class:: west.commands.WestCommand +.. autoclass:: west.commands.WestCommand Instance attributes: @@ -223,7 +223,7 @@ Since west v0.13, the recommended class for reading this is :py:class:`west.configuration.Configuration`. Note that if you are writing a :ref:`west extension `, you can -access the current ``Configuration`` object as ``self.configuration``. See +access the current ``Configuration`` object as ``self.config``. See :py:class:`west.commands.WestCommand`. Configuration API From 43519686f8bb809d8e353ecbc2e99b92dbb600d0 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 9 Jan 2023 15:46:59 -0800 Subject: [PATCH 151/226] doc: add snippets documentation Document this new build system feature. Since its purpose is customizing application builds, the logical place for the main body of documentation is in a new snippets/ directory in doc/build/. Create that directory and add its initial documentation. Like boards and samples, however, we expect people to write documentation for each snippet within the directory that defines the snippet itself. Therefore, add a new top-level snippets/ directory and stub out the documentation needed to document individual snippets as well. Add documentation and cross-references in other required places as well. Signed-off-by: Marti Bolivar --- doc/develop/west/build-flash-debug.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index df8fe921..8fd68272 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -350,6 +350,11 @@ build the specific target for the target, for example:: west build --sysbuild --domain hello_world --target help +Use a snippet +------------- + +See :ref:`using-snippets`. + .. _west-building-config: Configuration Options From abc1aca272058ffe1242fbcfdd7fed56585d07fd Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 24 Mar 2023 11:55:44 +0000 Subject: [PATCH 152/226] doc: develop: west: sign: Add details on extending signing Adds details on how to extend/replace the CMake files used for west sign operations. Signed-off-by: Jamie McCrae --- doc/develop/west/sign.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 6a554174..d0d17992 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -89,6 +89,29 @@ Whether ``west flash`` supports this feature depends on your runner. The does not support this flow and you would like it to, please send a patch or file an issue for adding support. +.. _west-extending-signing: + +Extending signing externally +**************************** + +The signing script used when running ``west flash`` can be extended or replaced +to change features or introduce different signing mechanisms. By default with +MCUboot enabled, signing is setup by the :file:`cmake/mcuboot.cmake` file in +Zephyr which adds extra post build commands for generating the signed images. +The file used for signing can be replaced by adjusting the ``SIGNING_SCRIPT`` +property on the `zephyr_property_target`, ideally done by a module using: + +.. code-block:: cmake + + if(CONFIG_BOOTLOADER_MCUBOOT) + set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/custom_signing.cmake) + endif() + +This will include the custom signing CMake file instead of the default Zephyr +one when projects are built with MCUboot signing support enabled. The base +Zephyr MCUboot signing file can be used as a reference for creating a new +signing system or extending the default behaviour. + .. _MCUboot: https://mcuboot.com/ From dd5c0dbc6b207fb77285f9f7a5e21ead2eea01a8 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 24 Feb 2023 07:13:23 +0000 Subject: [PATCH 153/226] intel_adsp: move `west sign` from `west flash` to earlier `west build` Invoking `west sign` in `west build` accelerates twister because `west build` is run in parallel, see rationale in superseded and very different (CMake-based) PR #52942. To maximize backwards compatibility: - `west sign` is optional in `west build` - `west flash` will sign (again) if any rimage --option is passed Signed-off-by: Marc Herbert --- doc/develop/west/sign.rst | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index d0d17992..13dfaa4d 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -117,3 +117,54 @@ signing system or extending the default behaviour. .. _imgtool: https://pypi.org/project/imgtool/ + + +rimage +****** + +rimage configuration uses a different approach that does not rely on Kconfig or CMake +but on :ref:`west config` instead, similar to +:ref:`west-building-cmake-config`. + +Signing involves a number of "wrapper" scripts stacked on top of each other: ``west +flash`` invokes ``west build`` which invokes ``cmake`` and ``ninja`` which invokes +``west sign`` which invokes ``imgtool`` or `rimage`_. As long as the signing +parameters desired are the default ones and fairly static, these indirections are +not a problem. On the other hand, passing ``imgtool`` or ``rimage`` options through +all these layers can causes issues typical when the layers don't abstract +anything. First, this usually requires boilerplate code in each layer. Quoting +whitespace or other special characters through all the wrappers can be +difficult. Reproducing a lower ``west sign`` command to debug some build-time issue +can be very time-consuming: it requires at least enabling and searching verbose +build logs to find which exact options were used. Copying these options from the +build logs can be unreliable: it may produce different results because of subtle +environment differences. Last and worst: new signing feature and options are +impossible to use until more boilerplate code has been added in each layer. + +To avoid these issues, ``rimage`` parameters can bet set in ``west config`` +instead. Here's a ``workspace/.west/config`` example: + +.. code-block:: ini + + [sign] + # Not needed when invoked from CMake + tool = rimage + + [rimage] + # Quoting is optional and works like in Unix shells + # Not needed when rimage can be found in the default PATH + path = "/home/me/zworkspace/build-rimage/rimage" + + # Not needed when using the default development key + extra-args = -i 4 -k 'keys/key argument with space.pem' + +In order to support quoting, values are parsed by Python's ``shlex.split()`` like in +:ref:`west-building-cmake-args`. + +The ``extra-args`` are passed directly to the ``rimage`` command. The example +above has the same effect as appending them on command line after ``--`` like this: +``west sign --tool rimage -- -i 4 -k 'keys/key argument with space.pem'``. In case +both are used, the command-line arguments go last. + +.. _rimage: + https://github.com/thesofproject/rimage From 5bf36ae6285a1405fb534238431e53e832f26672 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Sat, 8 Apr 2023 00:10:17 +0000 Subject: [PATCH 154/226] docs/build-flash-debug: expand one-time CMake arguments section - Change "re-run CMake" to "re-run CMake configuration steps" because `west build -v ...` displays `cmake --build ...` every time which can confuse non-experts. - Explain what is the actual issue with re-configuring: it makes the incremental builds slower. But not much slower: ``` $ west build -b qemu_x86 samples/hello_world/ -DCONFIG_OUTPUT_STAT=y [133/133] Linking C executable zephyr/zephyr.elf $ west build -b qemu_x86 samples/hello_world/ -DCONFIG_OUTPUT_STAT=y [16/16] Linking C executable zephyr/zephyr.elf ``` - Explain that the best solution is to simply skip to the next section Signed-off-by: Marc Herbert --- doc/develop/west/build-flash-debug.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 8fd68272..44aa0bb5 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -208,11 +208,16 @@ build``, pass them after a ``--`` at the end of the command line. .. important:: Passing additional CMake arguments like this forces ``west build`` to re-run - CMake, even if a build system has already been generated. + the CMake build configuration step, even if a build system has already been + generated. This will make incremental builds slower (but still much faster + than building from scratch). After using ``--`` once to generate the build directory, use ``west build -d `` on subsequent runs to do incremental builds. + Alternatively, make your CMake arguments permanent as described in the next + section; it will not slow down incremental builds. + For example, to use the Unix Makefiles CMake generator instead of Ninja (which ``west build`` uses by default), run:: From 0140e3a0c0db15855d84b9817669498f10f2c4c9 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Wed, 5 Apr 2023 16:32:25 +0200 Subject: [PATCH 155/226] doc: modules: Clarify the difference between modules and projects Since this has been a source of confusion for a while now, add a small section to clarify the difference between modules and west projects. Signed-off-by: Carles Cufi --- doc/develop/west/basics.rst | 3 ++- doc/develop/west/manifest.rst | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/basics.rst b/doc/develop/west/basics.rst index 6137bf94..2695a4f8 100644 --- a/doc/develop/west/basics.rst +++ b/doc/develop/west/basics.rst @@ -88,7 +88,8 @@ projects By default, the Zephyr :ref:`build system ` uses west to get the locations of all the projects in the workspace, so any code they contain - can be used as :ref:`modules`. + can be used as :ref:`modules`. Note however that modules and projects + :ref:`are conceptually different `. extensions Any repository known to west (either the manifest repository or any project diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index d94e87e8..e823db45 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -160,7 +160,8 @@ The ``projects`` subsection contains a sequence describing the project repositories in the west workspace. Every project has a unique name. You can specify what Git remote URLs to use when cloning and fetching the projects, what revisions to track, and where the project should be stored on the local -file system. +file system. Note that west projects :ref:`are different from modules +`. Here is an example. We'll assume the ``remotes`` given above. From c9be6785694e4c0074918a2b4374e6a287e0a71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 19 May 2023 11:18:11 -0700 Subject: [PATCH 156/226] doc: west: apis: fix MalformedConfig autoclass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was moved to west.configuration in v0.14.0. It happens to work in the current API docs because the west.manifest module also imports this class internally, but that's not where it's defined. Signed-off-by: Martí Bolívar --- doc/develop/west/west-apis.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index e3e7e393..0aeb33d6 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -484,10 +484,10 @@ Manifest and sub-objects Exceptions ========== -.. autoclass:: west.manifest.MalformedManifest +.. autoclass:: west.configuration.MalformedConfig :show-inheritance: -.. autoclass:: west.manifest.MalformedConfig +.. autoclass:: west.manifest.MalformedManifest :show-inheritance: .. autoclass:: west.manifest.ManifestVersionError From 3e9c0f0845d660e72d61843916d5c132a8cda953 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 17 May 2023 13:24:35 +0200 Subject: [PATCH 157/226] doc: introduce EXTRA_CONF_FILE and EXTRA_DTC_OVERLAY_FILE Introduce EXTRA_CONF_FILE and EXTRA_DTC_OVERLAY_FILE and remove old references to OVERLAY_CONFIG. Signed-off-by: Torsten Rasmussen --- doc/develop/west/build-flash-debug.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 44aa0bb5..b6809094 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -242,7 +242,7 @@ To set :ref:`DTC_OVERLAY_FILE ` to To merge the :file:`file.conf` Kconfig fragment into your build's :file:`.config`:: - west build -- -DOVERLAY_CONFIG=file.conf + west build -- -DEXTRA_CONF_FILE=file.conf .. _west-building-cmake-config: From fc7f3756196865385bc57f7e895e71b003279a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 23 May 2023 06:04:48 -0700 Subject: [PATCH 158/226] doc: west: clarify import example YAML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fine-tuning for clarity. Signed-off-by: Martí Bolívar --- doc/develop/west/manifest.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index e823db45..85ab9983 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -1926,14 +1926,18 @@ sections. The general case looks like this: manifest: projects: - name: foo - import: import-1 + import: + ... # import-1 - name: bar - import: import-2 + import: + ... # import-2 # ... - name: baz - import: import-N + import: + ... # import-N self: - import: self-import + import: + ... # self-import Import keys are optional. If any of ``import-1, ..., import-N`` are missing, west will not import additional manifest data from that project. If @@ -1970,6 +1974,8 @@ This process recurses if necessary. E.g., if ``import-1`` produces a manifest file that contains an ``import`` key, it is resolved recursively using the same rules before its contents are processed further. +The following sections describe these outcomes. + Projects -------- From 1426c6fe2048d285175b529a715bb2ed6126c894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 23 May 2023 07:10:47 -0700 Subject: [PATCH 159/226] doc: west: improve "version:" documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate information from release-notes.rst into a new table describing the manifest file format features which were introduced in each version of west. Signed-off-by: Martí Bolívar --- doc/develop/west/manifest.rst | 96 ++++++++++++++++++++++++------ doc/develop/west/release-notes.rst | 4 ++ 2 files changed, 81 insertions(+), 19 deletions(-) diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index 85ab9983..11f45ac0 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -412,35 +412,93 @@ The available ``self`` keys and their usage are in the following table. Version ======= -The ``version`` subsection can be used to mark the lowest version of the -manifest file schema that can parse this file's data: +The ``version`` subsection declares that the manifest file uses features which +were introduced in some version of west. Attempts to load the manifest with +older versions of west will fail with an error message that explains the +minimum required version of west which is needed. + +Here is an example: .. code-block:: yaml manifest: - version: "0.10" - # marks that this file uses version 0.10 of the west manifest + # Marks that this file uses version 0.10 of the west manifest # file format. + # + # An attempt to load this manifest file with west v0.8.0 will + # fail with an error message saying that west v0.10.0 or + # later is required. + version: "0.10" + +The pykwalify schema :file:`manifest-schema.yml` in the `west source code +repository`_ is used to validate the manifest section. + +.. _west source code repository: + https://github.com/zephyrproject-rtos/west + +Here is a table with the valid ``version`` values, along with information +about the manifest file features that were introduced in that version. + +.. list-table:: + :header-rows: 1 + :widths: 1 4 + + * - ``version`` + - New features -The pykwalify schema :file:`manifest-schema.yml` in the west source code -repository is used to validate the manifest section. The current manifest -``version`` is 0.13, which is supported by west version v0.13.x. + * - ``"0.7"`` + - Initial support for the ``version`` feature. All manifest file features + that are not otherwise mentioned in this table were introduced in + west v0.7.0 or earlier. -The ``version`` value may be any one of these values: ``"0.7"``, ``"0.8"``, -``"0.9"``, ``"0.10"``, ``"0.12"``, ``"0.13"``. West v0.11 did not include any -new features which broke the previous schema, so ``"0.11"`` **is not** a valid -schema version. + * - ``"0.8"`` + - Support for ``import: path-prefix:`` (:ref:`west-manifest-import-map`) + + * - ``"0.9"`` + - **Use of west v0.9.x is discouraged**. + + This schema version is provided to allow users to explicitly request + compatibility with west :ref:`west_0_9_0`. However, west + :ref:`west_0_10_0` and later have incompatible behavior for features + that were introduced in west v0.9.0. You should ignore version "0.9" if + possible. + + * - ``"0.10"`` + + - Support for: + + - ``submodules:`` in ``projects:`` (:ref:`west-manifest-submodules`) + - ``manifest: group-filter:``, and ``groups:`` in ``projects:`` + (:ref:`west-manifest-groups`) + - The ``import:`` feature now supports ``allowlist:`` and + ``blocklist:``; these are respectively recommended as replacements for + older names as part of a general Zephyr-wide inclusive language + change. The older key names are still supported for backwards + compatibility. (:ref:`west-manifest-import`, + :ref:`west-manifest-import-map`) + + * - ``"0.12"`` + - Support for ``userdata:`` in ``projects:`` (:ref:`west-project-userdata`) + + * - ``"0.13"`` + - Support for ``self: userdata:`` (:ref:`west-project-userdata`) + +.. note:: -West v0.10.x can load manifests with any of these ``version`` values, while -west v0.9.x can only load versions up to ``"0.9"``, and so on. + Versions of west without any new features in the manifest file format do not + change the list of valid ``version`` values. For example, ``version: + "0.11"`` is **not** valid, because west v0.11.x did not introduce new + manifest file format features. -West halts with an error if you ask it to load a manifest file written in a -version it cannot handle. +Quoting the ``version`` value as shown above forces the YAML parser to treat it +as a string. Without quotes, ``0.10`` in YAML is just the floating point value +``0.1``. You can omit the quotes if the value is the same when cast to string, +but it's best to include them. Always use quotes if you're not sure. -Quoting the ``version`` value as shown above forces the YAML parser to treat -it as a string. Without quotes, ``0.10`` in YAML is just the floating point -value ``0.1``. You can omit the quotes if the value is the same when cast to -string, but it's best to include them. Always use quotes if you're not sure. +If you do not include a ``version`` in your manifest, each new release of west +assumes that it should try to load it using the features that were available in +that release. This may result in error messages that are harder to understand +if that version of west is too old to load the manifest. Group-filter ============ diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index c4d9d161..0f4015d8 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -293,6 +293,8 @@ New features: ``master`` to ``main`` without breaking scripts that do not provide this option. +.. _west_0_10_0: + v0.10.0 ******* @@ -342,6 +344,8 @@ Other changes: this combination have changed starting with v0.10.x. See the v0.10.0 release notes above for more information. +.. _west_0_9_0: + v0.9.0 ****** From c2bd18c92ee81236cf40ba8fd89c18fdd6557fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 31 May 2023 14:42:14 -0700 Subject: [PATCH 160/226] doc: west: troubleshooting: fix path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the text align with the code block. Signed-off-by: Martí Bolívar --- doc/develop/west/troubleshooting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/troubleshooting.rst b/doc/develop/west/troubleshooting.rst index 7f016df2..8181d8cd 100644 --- a/doc/develop/west/troubleshooting.rst +++ b/doc/develop/west/troubleshooting.rst @@ -29,7 +29,7 @@ something like this: The ``git fetch`` command example in the last line above is what needs to succeed. -One strategy is to go to ``/some/directory``, copy/paste and run the entire +One strategy is to go to ``/path/to/your/project``, copy/paste and run the entire ``git fetch`` command, then debug from there using the documentation for your credential storage helper. From 13217f22af55fd872ab6d8ec275868348f0386b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 1 Jun 2023 14:48:09 -0700 Subject: [PATCH 161/226] doc: west: fix group filter documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs about how this works are inconsistent. Fix it by adjusting the docs so they all match the implementation and are consistent with each other. Earlier in this page: Manifest files which appear earlier in the import order have higher precedence and are therefore concatenated later into the final group-filter. Where for "import order" we have: Importing is done in this order: 1. Manifests from self-import are imported first. 2. The top-level manifest file’s definitions are handled next. 3. Manifests from import-1, …, import-N, are imported in that order. Therefore, "filter-1 to filter-N" is the wrong precedence order. It should be "filter-N to filter-1", so that filter-N is lower precedence than filter-1. That is consistent with import-1 happening before import-N. Signed-off-by: Martí Bolívar --- doc/develop/west/manifest.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index 11f45ac0..2253565a 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -2099,8 +2099,8 @@ In other words, let: - the submanifests resolved from ``import-1`` through ``import-N`` have group filters ``filter-1`` through ``filter-N`` respectively -The final resolved ``group-filter`` value is then ``filter1 + filter-2 + ... + -filter-N + top-filter + self-filter``, where ``+`` here refers to list +The final resolved ``group-filter`` value is then ``filterN + ... + filter-2 + +filter-1 + top-filter + self-filter``, where ``+`` here refers to list concatenation. .. important:: From b216752160017d7cb22cb4fc69e27170338cb6df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 1 Jun 2023 17:10:46 -0700 Subject: [PATCH 162/226] doc: west: v1.0.1 and v1.1.0 release notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add release notes and update relevant documentation pages for these releases. Signed-off-by: Martí Bolívar --- doc/develop/west/built-in.rst | 1 + doc/develop/west/config.rst | 57 ++++++++++++++++++ doc/develop/west/manifest.rst | 94 +++++++++++++++++++----------- doc/develop/west/release-notes.rst | 55 +++++++++++++++++ doc/develop/west/west-apis.rst | 3 + 5 files changed, 176 insertions(+), 34 deletions(-) diff --git a/doc/develop/west/built-in.rst b/doc/develop/west/built-in.rst index c84dc986..085a37fd 100644 --- a/doc/develop/west/built-in.rst +++ b/doc/develop/west/built-in.rst @@ -251,6 +251,7 @@ detailed help. - ``west diff``: run ``git diff`` in local project repositories - ``west status``: run ``git status`` in local project repositories - ``west forall``: run an arbitrary command in local project repositories +- ``west compare``: compare the state of the workspace against the manifest Other built-in commands *********************** diff --git a/doc/develop/west/config.rst b/doc/develop/west/config.rst index 35b10de0..594b54cb 100644 --- a/doc/develop/west/config.rst +++ b/doc/develop/west/config.rst @@ -149,6 +149,63 @@ commands are documented in the pages for those commands. - String, relative path from the :term:`west workspace` root directory to the manifest repository used by ``west update`` and other commands which parse the manifest. Set locally by ``west init``. + * - ``manifest.project-filter`` + - Comma-separated list of strings. + + The option's value is a comma-separated list of regular expressions, + each prefixed with ``+`` or ``-``, like this: + + .. code-block:: none + + +re1,-re2,-re3 + + Project names are matched against each regular expression (``re1``, + ``re2``, ``re3``, ...) in the list, in order. If the entire project name + matches the regular expression, that element of the list either + deactivates or activates the project. The project is deactivated if the + element begins with ``-``. The project is activated if the element + begins with ``+``. (Project names cannot contain ``,`` if this option is + used, so the regular expressions do not need to contain a literal ``,`` + character.) + + If a project's name matches multiple regular expressions in the list, + the result from the last regular expression is used. For example, + if ``manifest.project-filter`` is: + + .. code-block:: none + + -hal_.*,+hal_foo + + Then a project named ``hal_bar`` is inactive, but a project named + ``hal_foo`` is active. + + If a project is made inactive or active by a list element, the project + is active or not regardless of whether any or all of its groups are + disabled. (This is currently the only way to make a project that has no + groups inactive.) + + Otherwise, i.e. if a project does not match any regular expressions in + the list, it is active or inactive according to the usual rules related + to its groups (see :ref:`west-project-group-examples` for examples in + that case). + + Within an element of a ``manifest.project-filter`` list, leading and + trailing whitespace are ignored. That means these example values + are equivalent: + + .. code-block:: none + + +foo,-bar + +foo , -bar + + Any empty elements are ignored. That means these example values are + equivalent: + + .. code-block:: none + + +foo,,-bar + +foo,-bar + * - ``update.fetch`` - String, one of ``"smart"`` (the default behavior starting in v0.6.1) or ``"always"`` (the previous behavior). If set to ``"smart"``, the diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index 2253565a..3f2fa74e 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -483,6 +483,10 @@ about the manifest file features that were introduced in that version. * - ``"0.13"`` - Support for ``self: userdata:`` (:ref:`west-project-userdata`) + * - ``"1.0"`` + - Identical to ``"0.13"``, but available for use by users that + do not wish to use a ``"0.x"`` version field. + .. note:: Versions of west without any new features in the manifest file format do not @@ -505,14 +509,56 @@ Group-filter See :ref:`west-manifest-groups`. +.. _west-active-inactive-projects: + +Active and Inactive Projects +**************************** + +Projects defined in the west manifest can be *inactive* or *active*. The +difference is that an inactive project is generally ignored by west. For +example, ``west update`` will not update inactive projects, and ``west list`` +will not print information about them by default. As another example, any +:ref:`west-manifest-import` in an inactive project will be ignored by west. + +There are two ways to make a project inactive: + +1. Using the ``manifest.project-filter`` configuration option. If a project is + made active or inactive using this option, then the rules related to making + a project inactive using its ``groups:`` are ignored. That is, if a regular + expression in ``manifest.project-filter`` applies to a project, the + project's groups have no effect on whether it is active or inactive. + + See the entry for this option in :ref:`west-config-index` for details. + +2. Otherwise, if a project has groups, and they are all disabled, then the + project is inactive. + + See the following section for details. + .. _west-manifest-groups: -Project Groups and Active Projects -********************************** +Project Groups +************** You can use the ``groups`` and ``group-filter`` keys briefly described -:ref:`above ` to place projects into groups, and filter -which groups are enabled. These keys appear in the manifest like this: +:ref:`above ` to place projects into groups, and to +enable or disable groups. + +For example, this lets you run a ``west forall`` command only on the projects +in the group by using ``west forall --group``. This can also let you make +projects inactive; see the previous section for more information on inactive +projects. + +The next section introduces project groups. The following section describes +:ref:`west-enabled-disabled-groups`. There are some basic examples in +:ref:`west-project-group-examples`. Finally, :ref:`west-group-filter-imports` +provides a simplified overview of how ``group-filter`` interacts with the +:ref:`west-manifest-import` feature. + +Groups Basics +============= + +The ``groups:`` and ``group-filter:`` keys appear in the manifest like this: .. code-block:: yaml @@ -522,22 +568,11 @@ which groups are enabled. These keys appear in the manifest like this: groups: ... group-filter: ... -You can enable or disable project groups using ``group-filter``. Projects whose -groups are all disabled are *inactive*; west essentially ignores inactive -projects unless explicitly requested not to. - -The next section introduces project groups; the following sections describe -:ref:`west-enabled-disabled-groups` and :ref:`west-active-inactive-projects`. -There are some basic examples in :ref:`west-project-group-examples`. - -Finally, :ref:`west-group-filter-imports` provides a simplified overview of how -``group-filter`` interacts with the :ref:`west-manifest-import` feature. +The ``groups`` key's value is a list of group names. Group names are strings. -Project Groups -============== - -Inside ``manifest: projects:``, you can add a project to one or more groups. -The ``groups`` key is a list of group names. Group names are strings. +You can enable or disable project groups using ``group-filter``. Projects whose +groups are all disabled, and which are not otherwise made active by a +``manifest.project-filter`` configuration option, are inactive. For example, in this manifest fragment: @@ -569,7 +604,7 @@ contain these characters elsewhere in their names. For example, ``foo-bar`` and Group names are otherwise arbitrary strings. Group names are case sensitive. As a restriction, no project may use both ``import:`` and ``groups:``. (This -avoids some edge cases whose semantics are difficult to specify.) +is necessary to avoid some pathological edge cases.) .. _west-enabled-disabled-groups: @@ -630,20 +665,6 @@ You can think of this as if the ``manifest.group-filter`` configuration option is appended to the ``manifest: group-filter:`` list from YAML, with "last entry wins" semantics. -.. _west-active-inactive-projects: - -Active and Inactive Projects -============================ - -All projects are *active* by default. Projects with no groups are always -active. A project is *inactive* if all of its groups are disabled. This is the -only way to make a project inactive. - -Most west commands that operate on projects will ignore inactive projects by -default. For example, :ref:`west-update` when run without arguments will not -update inactive projects. As another example, running ``west list`` without -arguments will not print information for inactive projects. - .. _west-project-group-examples: Project Group Examples @@ -656,6 +677,11 @@ projects. The examples use both ``manifest: group-filter:`` YAML lists and Note that the ``defaults`` and ``remotes`` data in the following manifests isn't relevant except to make the examples complete and self-contained. +.. note:: + + In all of the examples that follow, the ``manifest.project-filter`` option + is assumed to be unset. + Example 1: no disabled groups ----------------------------- diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 0f4015d8..5f46dfe1 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -3,6 +3,61 @@ West Release Notes ################## +v1.1.0 +****** + +Major changes: + +- ``west compare``: new command that compares the state of the + workspace against the manifest. + +- Support for a new ``manifest.project-filter`` configuration option. + See :ref:`west-config-index` for details. The ``west manifest --freeze`` + and ``west manifest --resolve`` commands currently cannot be used when + this option is set. This restriction can be removed in a later release. + +- Project names which contain comma (``,``) or whitespace now generate + warnings. These warnings are errors if the new ``manifest.project-filter`` + configuration option is set. The warnings may be promoted to errors in a + future major version of west. + +Other changes: + +- ``west forall`` now takese a ``--group`` argument that can be used + to restrict the command to only run in one or more groups. Run + ``west help forall`` for details. + +- All west commands will now output log messages from west API modules at + warning level or higher. In addition, the ``--verbose`` argument to west + can be used once to include informational messages, or twice to include + debug messages, from all commands. + +Bug fixes: + +- Various improvements to error messages, debug logging, and error handling. + +API changes: + +- ``west.manifest.Manifest.is_active()`` now respects the + ``manifest.project-filter`` configuration option's value. + +v1.0.1 +****** + +Major changes: + +- Manifest schema version "1.0" is now available for use in this release. This + is identical to the "0.13" schema version in terms of features, but can be + used by applications that do not wish to use a "0.x" manifest "version:" + field. See :ref:`west-manifest-schema-version` for details on this feature. + +Bug fixes: + +- West no longer exits with a successful error code when sent an + interrupt signal. Instead, it exits with a platform-specific + error code and signals to the calling environment that the + process was interrupted. + v1.0.0 ****** diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index 0aeb33d6..ec60bc6f 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -384,6 +384,9 @@ Manifest and sub-objects .. versionadded:: 0.7.0 .. automethod:: is_active .. versionadded:: 0.9.0 + .. versionchanged:: 1.1.0 + This respects the ``manifest.project-filter`` configuration + option. See :ref:`west-config-index`. .. autoclass:: west.manifest.ImportFlag :members: From bad97f5d79f17e10fad9b38f78c733451b5a3272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 6 Jun 2023 19:11:15 +0200 Subject: [PATCH 163/226] west: doc: update link to SPDX doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixed 404 link to SPDX documentation Signed-off-by: Benjamin Cabé --- doc/develop/west/zephyr-cmds.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 7bab6e20..d1d96d07 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -138,7 +138,7 @@ source files that are compiled to generate the built library files. document, :file:`sdk.spdx`, which lists header files included from the SDK. .. _SPDX specification clause 6: - https://spdx.github.io/spdx-spec/document-creation-information/ + https://spdx.github.io/spdx-spec/v2.2.2/document-creation-information/ .. _west-blobs: From aedc275a62cbe88eb233477b88dbd6026ced0a52 Mon Sep 17 00:00:00 2001 From: Andreas Deininger Date: Thu, 3 Aug 2023 21:11:31 +0200 Subject: [PATCH 164/226] documentation: Fix several typos Correcting typos in various documentation files Signed-off-by: Andreas Deininger --- doc/develop/west/release-notes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 5f46dfe1..98d67da9 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -361,7 +361,7 @@ New features: Bug fixes: - West now checks that the manifest schema version is one of the explicitly - allowed vlaues documented in :ref:`west-manifest-schema-version`. The old + allowed values documented in :ref:`west-manifest-schema-version`. The old behavior was just to check that the schema version was newer than the west version where the ``manifest: version:`` key was introduced. This incorrectly allowed invalid schema versions, like ``0.8.2``. From 369d11e467b3399afa7e963fa75f44133d2b6257 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Tue, 22 Aug 2023 18:58:44 +0300 Subject: [PATCH 165/226] west: sign: do not make rimage configuration and platform name mandatory Now, if the rimage target (meaning rimage configuration and platform name) is not defined in board.cmake the sign script returns fatal error. Change this to a warning since there are configurations that are not using 'west sign' or is used just to glue the headers of the final image. Also, update the documentation accordingly. Signed-off-by: Iuliana Prodan Signed-off-by: Marc Herbert --- doc/develop/west/sign.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 13dfaa4d..0606da34 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -5,7 +5,9 @@ Signing Binaries The ``west sign`` :ref:`extension ` command can be used to sign a Zephyr application binary for consumption by a bootloader using an -external tool. Run ``west sign -h`` for command line help. +external tool. In some configurations, ``west sign`` is also used to invoke +an external, post-processing tool that "stitches" the final components of +the image together. Run ``west sign -h`` for command line help. MCUboot / imgtool ***************** From 36352730553105e621ab87f3fa7d0437aa99f7c8 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 15 Aug 2023 12:59:29 +0300 Subject: [PATCH 166/226] doc: west: Remove empty Footnotes rubric Remove empty rubric. Cross-linking markups are not included in Footnotes. Signed-off-by: Andrei Emeltchenko --- doc/develop/west/build-flash-debug.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index b6809094..abe26614 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -739,8 +739,6 @@ debugging. This can of course also be accomplished using the usual targets provided by Zephyr's build system (in fact, that's how these commands do it). -.. rubric:: Footnotes - .. _cmake(1): https://cmake.org/cmake/help/latest/manual/cmake.1.html From bf969ef0a067a7e6c36750d9c6f517d523674336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 6 Sep 2023 10:25:28 +0200 Subject: [PATCH 167/226] doc: Migrate subsys/ code samples to new Sphinx extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This migrates the subsys code samples to the new Sphinx code-sample extension, making it easier to find relevant samples when browsing API reference. Signed-off-by: Benjamin Cabé --- doc/develop/west/sign.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 0606da34..44193d46 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -42,7 +42,7 @@ Notes on the above commands: - The ``CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`` value is the insecure default provided and used by by MCUboot for development and testing - You can change the ``hello_world`` application directory to any other - application that can be loaded by MCUboot, such as the :ref:`smp_svr_sample` + application that can be loaded by MCUboot, such as the :zephyr:code-sample:`smp-svr` sample. For more information on these and other related configuration options, see: From 3a62ecec1b0a957fbaf70666440eeff1c9c29075 Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Sat, 25 Mar 2023 22:52:41 +0300 Subject: [PATCH 168/226] doc: bindesc: Add documentation for binary descriptors Add documentation for binary descriptors under "OS Services" Signed-off-by: Yonatan Schachter --- doc/develop/west/zephyr-cmds.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index d1d96d07..056d22e4 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -185,3 +185,28 @@ Twister can then be invoked via west as follows:: west twister -help west twister -T tests/ztest/base + +.. _west-bindesc: + +Working with binary descriptors: ``west bindesc`` +************************************************* + +The ``bindesc`` command allows users to read :ref:`binary descriptors` +of executable files. It currently supports ``.bin``, ``.hex``, ``.elf`` and ``.uf2`` files +as input. + +You can search for a specific descriptor in an image, for example:: + + west bindesc search KERNEL_VERSION_STRING build/zephyr/zephyr.bin + +You can search for a custom descriptor by type and ID, for example:: + + west bindesc custom_search STR 0x200 build/zephyr/zephyr.bin + +You can dump all of the descriptors in an image using:: + + west bindesc dump build/zephyr/zephyr.bin + +You can list all known standard descriptor names using:: + + west bindesc list From a28d395007d9e0342e18bf635419d0caafd1fc1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 11 Oct 2023 09:30:28 -0700 Subject: [PATCH 169/226] doc: west: build: fix info on --pristine default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit commit c19c6fb438b98e54d38eeff4a606d6d9a3d801c8 ("Revert "scripts: west build: default build.pristine to auto""), we set the default --pristine value back to 'never', but the documentation never got updated. Fix it. Signed-off-by: Martí Bolívar --- doc/develop/west/build-flash-debug.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index abe26614..0f9f15ef 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -177,8 +177,12 @@ it the value ``always``. For example, these commands are equivalent:: west build -p -b reel_board samples/hello_world west build -p=always -b reel_board samples/hello_world -By default, ``west build`` applies a heuristic to detect if the build directory -needs to be made pristine. This is the same as using ``--pristine=auto``. +By default, ``west build`` makes no attempt to detect if the build directory +needs to be made pristine. This can lead to errors if you do something like +try to re-use a build directory for a different ``--board``. + +Using ``--pristine=auto`` makes ``west build`` detect some of these situations +and make the build directory pristine before trying the build. .. tip:: From 88718b2dafcb9ea2b2f4c0830e489b30a0575bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 6 Oct 2023 10:50:32 -0700 Subject: [PATCH 170/226] doc: west: sort built-in project commands by name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For convenience Signed-off-by: Martí Bolívar --- doc/develop/west/built-in.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/develop/west/built-in.rst b/doc/develop/west/built-in.rst index 085a37fd..150e4ec7 100644 --- a/doc/develop/west/built-in.rst +++ b/doc/develop/west/built-in.rst @@ -245,13 +245,13 @@ West has a few more commands for managing the projects in the workspace, which are summarized here. Run ``west -h`` for detailed help. +- ``west compare``: compare the state of the workspace against the manifest +- ``west diff``: run ``git diff`` in local project repositories +- ``west forall``: run an arbitrary command in local project repositories - ``west list``: print a line of information about each project in the manifest, according to a format string - ``west manifest``: manage the manifest file. See :ref:`west-manifest-cmd`. -- ``west diff``: run ``git diff`` in local project repositories - ``west status``: run ``git status`` in local project repositories -- ``west forall``: run an arbitrary command in local project repositories -- ``west compare``: compare the state of the workspace against the manifest Other built-in commands *********************** From 1c770338bbbba21537a9b12618eeb6f3ce50fd94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 6 Oct 2023 10:51:27 -0700 Subject: [PATCH 171/226] doc: west: add docs for west grep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main documentation for the command itself is in the 'west help grep' output, so just add an entry in the list of built-in commands. Document the extra config options as well. Signed-off-by: Martí Bolívar --- doc/develop/west/built-in.rst | 1 + doc/develop/west/config.rst | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/doc/develop/west/built-in.rst b/doc/develop/west/built-in.rst index 150e4ec7..b54dbaad 100644 --- a/doc/develop/west/built-in.rst +++ b/doc/develop/west/built-in.rst @@ -248,6 +248,7 @@ detailed help. - ``west compare``: compare the state of the workspace against the manifest - ``west diff``: run ``git diff`` in local project repositories - ``west forall``: run an arbitrary command in local project repositories +- ``west grep``: search for patterns in local project repositories - ``west list``: print a line of information about each project in the manifest, according to a format string - ``west manifest``: manage the manifest file. See :ref:`west-manifest-cmd`. diff --git a/doc/develop/west/config.rst b/doc/develop/west/config.rst index 594b54cb..eae6c7e4 100644 --- a/doc/develop/west/config.rst +++ b/doc/develop/west/config.rst @@ -135,6 +135,24 @@ commands are documented in the pages for those commands. stdout is a terminal. * - ``commands.allow_extensions`` - Boolean, default ``true``, disables :ref:`west-extensions` if ``false`` + * - ``grep.color`` + - String, default empty. Set this to ``never`` to disable ``west grep`` + color output. If set, ``west grep`` passes the value to the grep tool's + ``--color`` option. + * - ``grep.tool`` + - String, one of ``"git-grep"`` (default), ``"ripgrep"``, or ``"grep"``. + The grep tool that ``west grep`` should use. + * - ``grep.-args`` + - String, default empty. The ```` part is a pattern that can be any + ``grep.tool`` value, so ``grep.ripgrep-args`` is an example + configuration option. If set, arguments that ``west grep`` should pass + to the corresponding grep tool. Run ``west help grep`` for details. + * - ``grep.-path`` + - String, default empty. The ```` part is a pattern that can be any + ``grep.tool`` value, so ``grep.ripgrep-path`` is an example + configuration option. The path to the corresponding tool that ``west + grep`` should use instead of searching for the command. Run ``west help + grep`` for details. * - ``manifest.file`` - String, default ``west.yml``. Relative path from the manifest repository root directory to the manifest file used by ``west init`` and other From d9146a9bfe0ff8aa616c3ef39e10b8eec6171e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 6 Oct 2023 11:24:15 -0700 Subject: [PATCH 172/226] doc: west: sort west.manifest.Project info by release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For legibility. Signed-off-by: Martí Bolívar --- doc/develop/west/west-apis.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index ec60bc6f..ff03f907 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -396,10 +396,6 @@ Manifest and sub-objects .. (note: attributes are part of the class docstring) - .. versionchanged:: 0.8.0 - The *west_commands* attribute is now always a list. In previous - releases, it could be a string or ``None``. - .. versionchanged:: 0.7.0 The *remote* attribute was removed. Its semantics could no longer be preserved when support for manifest ``import`` keys was added. @@ -407,6 +403,10 @@ Manifest and sub-objects .. versionadded:: 0.7.0 The *remote_name* and *name_and_path* attributes. + .. versionchanged:: 0.8.0 + The *west_commands* attribute is now always a list. In previous + releases, it could be a string or ``None``. + .. versionadded:: 0.9.0 The *group_filter* and *submodules* attributes. From 028abd9569b977a0f1981536850b8eb63f84826c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 6 Oct 2023 11:26:18 -0700 Subject: [PATCH 173/226] doc: west: manifest file format changes for v1.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information about changes to the file format. Signed-off-by: Martí Bolívar --- doc/develop/west/manifest.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index 3f2fa74e..bb057272 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -174,9 +174,13 @@ Here is an example. We'll assume the ``remotes`` given above. # [... same remotes as above...] projects: - name: proj1 + description: the first example project remote: remote1 path: extra/project-1 - name: proj2 + description: | + A multi-line description of the second example + project. repo-path: my-path remote: remote2 revision: v1.3 @@ -229,6 +233,10 @@ next. reserved values "west" or "manifest". The name must be unique in the manifest file. + * - ``description`` + - Optional, an informational description of the project. Added in + west v1.2.0. + * - ``remote``, ``url`` - Mandatory (one of the two, but not both). @@ -331,9 +339,13 @@ so far using ``defaults`` is: projects: - name: proj1 + description: the first example project path: extra/project-1 revision: master - name: proj2 + description: | + A multi-line description of the second example + project. repo-path: my-path remote: remote2 - name: proj3 @@ -487,6 +499,10 @@ about the manifest file features that were introduced in that version. - Identical to ``"0.13"``, but available for use by users that do not wish to use a ``"0.x"`` version field. + * - ``"1.2"`` + - Support for ``description:`` in ``projects:`` + (:ref:`west-manifests-projects`) + .. note:: Versions of west without any new features in the manifest file format do not From 40492003476ba5f1e6ccfc59704631b84cac49e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 6 Oct 2023 11:26:49 -0700 Subject: [PATCH 174/226] doc: west: API changes for v1.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are backwards compatible extensions in keeping with our promise to adhere to semantic versioning from now on. Signed-off-by: Martí Bolívar --- doc/develop/west/west-apis.rst | 40 ++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index ff03f907..306cef81 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -137,14 +137,39 @@ WestCommand .. automethod:: add_pre_run_hook .. versionadded:: 1.0.0 - .. automethod:: check_call + .. NOTE: the following 'method' (not 'automethod') directives were added for + expediency during the west v1.2 release time frame to work around a build + failure in this zephyr documentation that could not be fixed without + cutting a west point release. (The docstrings in west had some RST syntax + errors). + These should be reverted back to automethod calls at the next release. + + .. method:: check_call(args, **kwargs) + + Runs ``subprocess.check_call(args, **kwargs)`` after + logging the call at Verbosity.DBG_MORE`` level. + + .. versionchanged:: 1.2.0 + The *cwd* keyword argument was replaced with a catch-all ``**kwargs``. .. versionchanged:: 0.11.0 - .. automethod:: check_output + .. method:: check_output(args, **kwargs) + + Runs ``subprocess.check_output(args, **kwargs)`` after + logging the call at Verbosity.DBG_MORE level. + .. versionchanged:: 1.2.0 + The *cwd* keyword argument was replaced with a catch-all ``**kwargs``. .. versionchanged:: 0.11.0 + .. method:: run_subprocess(args, **kwargs) + + Runs ``subprocess.run(args, **kwargs)`` after logging + the call at Verbosity.DBG_MORE level. + + .. versionadded:: 1.2.0 + All subclasses must provide the following abstract methods, which are used to implement the above: @@ -158,15 +183,23 @@ WestCommand "quiet" mode for west commands in a future release: .. automethod:: dbg + .. versionchanged:: 1.2.0 + The *end* argument. .. versionadded:: 1.0.0 .. automethod:: inf + .. versionchanged:: 1.2.0 + The *end* argument. .. versionadded:: 1.0.0 .. automethod:: wrn + .. versionchanged:: 1.2.0 + The *end* argument. .. versionadded:: 1.0.0 .. automethod:: err + .. versionchanged:: 1.2.0 + The *end* argument. .. versionadded:: 1.0.0 .. automethod:: die @@ -413,6 +446,9 @@ Manifest and sub-objects .. versionadded:: 0.12.0 The *userdata* attribute. + .. versionadded:: 1.2.0 + The *description* attribute. + Constructor: .. automethod:: __init__ From e0e56ab6295c759133a036e978c4fb982d3679bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 6 Oct 2023 11:32:39 -0700 Subject: [PATCH 175/226] doc: west: release notes for v1.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main new features are a 'west grep' command and a new 'description:' field in the manifest file's 'projects:' elements. Rather than try to keep the version number in index.rst up to date, which it frequently is not, just delete the paragraph. Signed-off-by: Martí Bolívar --- doc/develop/west/index.rst | 3 -- doc/develop/west/release-notes.rst | 75 ++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/doc/develop/west/index.rst b/doc/develop/west/index.rst index 627267fb..7b5fd6b2 100644 --- a/doc/develop/west/index.rst +++ b/doc/develop/west/index.rst @@ -26,9 +26,6 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v1.0.y`` releases, and provide additional -context about the tool. - .. toctree:: :maxdepth: 1 diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 98d67da9..49dcc0a3 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -3,6 +3,81 @@ West Release Notes ################## +v1.2.0 +****** + +Major changes: + +- New ``west grep`` command for running a "grep tool" in your west workspace's + repositories. Currently, ``git grep``, `ripgrep`_, and standard ``grep`` are + supported grep tools. + + To run this command to get ``git grep foo`` results from all cloned, + active repositories, run: + + .. code-block:: console + + west grep foo + + Here are some other examples for running different grep commands + with ``west grep``: + + .. list-table:: + + * - ``git grep --untracked`` + - ``west grep --untracked foo`` + * - ``ripgrep`` + - ``west grep --tool ripgrep foo`` + * - ``grep --recursive`` + - ``west grep --tool grep foo`` + + To switch the default grep tool in your workspace, run the appropriate + command in this table: + + .. list-table:: + + * - ``ripgrep`` + - ``west config grep.tool ripgrep`` + * - ``grep`` + - ``west config grep.tool grep`` + + For more details, run ``west help grep``. + +Other changes: + +- The manifest file format now supports a ``description`` field in each + ``projects:`` element. See :ref:`west-manifests-projects` for examples. + +- ``west list --format`` now accepts ``{description}`` in the format + string, which prints the project's ``description:`` value. + +- ``west compare`` now always prints information about + :ref:`west-manifest-rev`. + +Bug fixes: + +- ``west init`` aborts if the destination directory already exists. + +API changes: + +- ``west.commands.WestCommand`` methods ``check_call()`` and + ``check_output()`` now take any kwargs that can be passed on + to the underlying subprocess function. + +- ``west.commands.WestCommand.run_subprocess()``: new wrapper + around ``subprocess.run()``. This could not be named ``run()`` + because ``WestCommand`` already had a method by this name. + +- ``west.commands.WestCommand`` methods ``dbg()``, ``inf()``, + ``wrn()``, and ``err()`` now all take an ``end`` kwarg, which + is passed on to the call to ``print()``. + +- ``west.manifest.Project`` now has a ``description`` attribute, + which contains the parsed value of the ``description:`` field + in the manifest data. + +.. _ripgrep: https://github.com/BurntSushi/ripgrep#readme + v1.1.0 ****** From ed93093b58524302bf7c3703ab3cb5c1e137e903 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Wed, 15 Nov 2023 11:10:16 +0100 Subject: [PATCH 176/226] doc: Fix double 'the' Fix double 'the' in all .rst documentation. Signed-off-by: Andrej Butok --- doc/develop/west/manifest.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index bb057272..ba0f9f29 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -248,7 +248,7 @@ next. remote Git repository. If the project has neither, the ``defaults`` section must specify a - ``remote``, which will be used as the the project's remote. Otherwise, + ``remote``, which will be used as the project's remote. Otherwise, the manifest is invalid. * - ``repo-path`` @@ -2049,7 +2049,7 @@ The ultimate outcomes of resolving manifest imports are: - a ``projects`` list, which is produced by combining the ``projects`` defined in the top-level file with those defined in imported files -- a set of extension commands, which are drawn from the the ``west-commands`` +- a set of extension commands, which are drawn from the ``west-commands`` keys in in the top-level file and any imported files - a ``group-filter`` list, which is produced by combining the top-level and any From ee6ea43394603eb82a72665777da4df493181498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 15 Nov 2023 16:29:08 +0100 Subject: [PATCH 177/226] doc: Fix occurrences of repeated words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Another round of repeated words cleanup. This commit tries to keep the diff minimal and line wrapping was mostly left intact in the touched files, as having them consistent across the documentation is probably the topic of a future tree-wide cleanup (or not) Signed-off-by: Benjamin Cabé --- doc/develop/west/manifest.rst | 4 ++-- doc/develop/west/release-notes.rst | 2 +- doc/develop/west/sign.rst | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index ba0f9f29..f989cdca 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -1124,7 +1124,7 @@ recursively update the project's Git submodules whenever it updates the project itself. If it's ``false`` or missing, it has no effect. For example, let's say you have a source code repository ``foo``, which has -some submodules, and you want ``west update`` to keep all of them them in sync, +some submodules, and you want ``west update`` to keep all of them in sync, along with another project named ``bar`` in the same workspace. You can do that with this manifest file: @@ -2050,7 +2050,7 @@ The ultimate outcomes of resolving manifest imports are: in the top-level file with those defined in imported files - a set of extension commands, which are drawn from the ``west-commands`` - keys in in the top-level file and any imported files + keys in the top-level file and any imported files - a ``group-filter`` list, which is produced by combining the top-level and any imported filters diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 49dcc0a3..951cc4c3 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -669,7 +669,7 @@ The developer-visible changes to the :ref:`west-apis` are: West now requires Python 3.6 or later. Additionally, some features may rely on Python dictionaries being insertion-ordered; this is only an implementation -detail in CPython 3.6, but is is part of the language specification as of +detail in CPython 3.6, but it is part of the language specification as of Python 3.7. v0.6.3 diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 44193d46..8cc55ffe 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -40,7 +40,7 @@ Notes on the above commands: - ``YOUR_BOARD`` should be changed to match your board - The ``CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`` value is the insecure default - provided and used by by MCUboot for development and testing + provided and used by MCUboot for development and testing - You can change the ``hello_world`` application directory to any other application that can be loaded by MCUboot, such as the :zephyr:code-sample:`smp-svr` sample. From a8fb59931f2aaf23ab561dab705df7096bb2df7e Mon Sep 17 00:00:00 2001 From: Thomas Gagneret Date: Tue, 5 Dec 2023 17:41:06 +0100 Subject: [PATCH 178/226] scripts: zspdx: Include modules as packages in zephyr.spdx The current zephyr.spdx does not contain the modules included in the build. This commit split the zephyr-sources package into multiple packages, one for each modules found by zephyr_module.py. Signed-off-by: Thomas Gagneret --- doc/develop/west/zephyr-cmds.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 056d22e4..f6b2322e 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -89,6 +89,8 @@ To use this command: This step ensures the build directory contains CMake metadata required for SPDX document generation. +#. Enable :file:`CONFIG_BUILD_OUTPUT_META` in your project. + #. Build your application using this pre-created build directory, like so: .. code-block:: bash From 2d8407154f3414f682f32e9b5a699021f039048f Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 26 Jan 2024 00:42:08 +0700 Subject: [PATCH 179/226] doc: develop: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the doc/develop directory. Signed-off-by: Pisit Sawangvonganan --- doc/develop/west/build-flash-debug.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 0f9f15ef..8356d95c 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -179,7 +179,7 @@ it the value ``always``. For example, these commands are equivalent:: By default, ``west build`` makes no attempt to detect if the build directory needs to be made pristine. This can lead to errors if you do something like -try to re-use a build directory for a different ``--board``. +try to reuse a build directory for a different ``--board``. Using ``--pristine=auto`` makes ``west build`` detect some of these situations and make the build directory pristine before trying the build. From 2fba820bb006efc3afa49de8be6b240a303f1b19 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 29 Jan 2024 09:14:02 +0000 Subject: [PATCH 180/226] doc: develop: west: sign: Add details on signing Adds details on how to do signing using sysbuild Signed-off-by: Jamie McCrae --- doc/develop/west/sign.rst | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 8cc55ffe..ef98631b 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -100,8 +100,23 @@ The signing script used when running ``west flash`` can be extended or replaced to change features or introduce different signing mechanisms. By default with MCUboot enabled, signing is setup by the :file:`cmake/mcuboot.cmake` file in Zephyr which adds extra post build commands for generating the signed images. -The file used for signing can be replaced by adjusting the ``SIGNING_SCRIPT`` -property on the `zephyr_property_target`, ideally done by a module using: +The file used for signing can be replaced from a sysbuild scope (if being used) +or from a zephyr/zephyr module scope, the priority of which is: + +* Sysbuild +* Zephyr property +* Default MCUboot script (if enabled) + +From sysbuild, ``-D_SIGNING_SCRIPT`` can be used to set a signing script +for a specific image or ``-DSIGNING_SCRIPT`` can be used to set a signing script +for all images, for example: + +.. code-block:: console + + west build -b -DSIGNING_SCRIPT= + +The zephyr property method is achieved by adjusting the ``SIGNING_SCRIPT`` property +on the `zephyr_property_target`, ideally from by a module by using: .. code-block:: cmake From fb8c07b9563d2d97d786385374e992a9b4475f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Mon, 18 Sep 2023 19:10:05 +0200 Subject: [PATCH 181/226] Documentation: Update shell completion doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove OS specific instructions, instructions depend on the shell and are the same across OS; - Add fish shell to the documentation. Signed-off-by: Théo Battrel --- doc/develop/west/install.rst | 65 ++++++++++++++++++-------------- doc/develop/west/zephyr-cmds.rst | 1 + 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/doc/develop/west/install.rst b/doc/develop/west/install.rst index e9f877cb..5ac0f6ef 100644 --- a/doc/develop/west/install.rst +++ b/doc/develop/west/install.rst @@ -48,50 +48,59 @@ APIs directly. See :ref:`west-apis` for details. Enabling shell completion ************************* -West currently supports shell completion in the following combinations of -platform and shell: +West currently supports shell completion in the following shells: -* Linux: bash -* macOS: bash -* Windows: not available +* bash +* zsh +* fish In order to enable shell completion, you will need to obtain the corresponding -completion script and have it sourced every time you enter a new shell session. +completion script and have it sourced. +Using the completion scripts: -To obtain the completion script you can use the ``west completion`` command:: +.. tabs:: - cd /path/to/zephyr/ - west completion bash > ~/west-completion.bash + .. group-tab:: bash -.. note:: + *One-time setup*: + + .. code-block:: bash + + source <(west completion bash) + + *Permanent setup*: + + .. code-block:: bash + + west completion bash > ~/west-completion.bash; echo "source ~/west-completion.bash" >> ~/.bashrc + + .. group-tab:: zsh + + *One-time setup*: + + .. code-block:: zsh + + source <(west completion zsh) - Remember to update your local copy of the completion script using ``west - completion`` when you update Zephyr. + *Permanent setup*: -Next, you need to import :file:`west-completion.bash` into your bash shell. + .. code-block:: zsh -On Linux, you have the following options: + west completion zsh > "${fpath[1]}/_west" -* Copy :file:`west-completion.bash` to :file:`/etc/bash_completion.d/`. -* Copy :file:`west-completion.bash` to - :file:`/usr/share/bash-completion/completions/`. -* Copy :file:`west-completion.bash` to a local folder and source it from your - :file:`~/.bashrc`. + .. group-tab:: fish -On macOS, you have the following options: + *One-time setup*: -* Copy :file:`west-completion.bash` to a local folder and source it from your - :file:`~/.bash_profile` -* Install the ``bash-completion`` package with ``brew``:: + .. code-block:: fish - brew install bash-completion + west completion fish | source - then source the main bash completion script in your :file:`~/.bash_profile`:: + *Permanent setup*: - source /usr/local/etc/profile.d/bash_completion.sh + .. code-block:: fish - and finally copy :file:`west-completion.bash` to - :file:`/usr/local/etc/bash_completion.d/`. + west completion fish > $HOME/.config/fish/completions/west.fish .. _PyPI: https://pypi.org/project/west/ diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index f6b2322e..6037cb42 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -39,6 +39,7 @@ It currently supports the following shells: - bash - zsh +- fish Additional instructions are available in the command's help:: From f1678873ad3aab8dc3aebdb00afcdffe5afc1eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 21 Mar 2024 21:58:48 +0100 Subject: [PATCH 182/226] west: spdx: introduce support for SPDX 2.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minor update to existing zspdx implementation to add support for PrimaryPackagePurpose introduced in SPDX 2.3. Signed-off-by: Benjamin Cabé --- doc/develop/west/zephyr-cmds.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 6037cb42..f10c4abe 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -74,7 +74,7 @@ See :zephyr_file:`share/zephyr-package/cmake` for details. Software bill of materials: ``west spdx`` ***************************************** -This command generates SPDX 2.2 tag-value documents, creating relationships +This command generates SPDX 2.3 tag-value documents, creating relationships from source files to the corresponding generated build files. ``SPDX-License-Identifier`` comments in source files are scanned and filled into the SPDX documents. From 5b122d77540556df6990351051b7ed63ec6efaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Szprejda?= Date: Thu, 7 Mar 2024 10:30:09 +0100 Subject: [PATCH 183/226] West: Add `west simulate` command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce `simulate `command for running samples on a simulator of choice. Initial implementation consists of one runner, dedicated for Renode. Signed-off-by: Michał Szprejda --- doc/develop/west/build-flash-debug.rst | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 8356d95c..4456151a 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -698,6 +698,49 @@ determined by the imported subclasses of ``ZephyrBinaryRunner``. runner implementations are in other submodules, such as ``runners.nrfjprog``, ``runners.openocd``, etc. +Simulating a board with: ``west simulate`` +****************************************** + +Basics +====== + +Currently the command supports only one runner which is using Renode, +but can be easily extended by adding other runners. + +From a Zephyr build directory, to run the built binary:: + + west simulate --runner=renode + +This will start Renode and configure simulation based on a default ``.resc`` script +for the current platform with the zephyr.elf file loaded by default. The simulation +then can be started by typing "start" or "s" in Renode's Monitor. This can also be +done by passing a command to Renode, using an argument provided by the runner: + + west simulate --runner=renode --renode-command start + +To pass an argument to Renode itself, for example to start Renode in console mode +intead of a separate window: + + west simulate --runner=renode --renode-arg="--console" + +From that point on Renode can be used normally in both console and window modes. +For details on using Renode see `Renode - documentation`_. + +.. _Renode - documentation: + http://docs.renode.io + +Runner-Specific Overrides +========================= + +To view all of the available options supported by the runners, as well +as their usage information, use ``--context`` (or``-H``):: + + west simulate --runner=renode --context + +To view all available options Renode supports, use:: + + west simulate --runner=renode --renode-help + Hacking ******* From 78ca3729c9b45784762c5a26f17bc073643bce0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Szprejda?= Date: Thu, 7 Mar 2024 10:35:06 +0100 Subject: [PATCH 184/226] West: Add `west robot` command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce `robot` command for running Robot Framework test suites. Initial implementation consists of one runner dedicated for renode-test, which is a Renode wrapper for running Robot tests. Signed-off-by: Michał Szprejda --- doc/develop/west/build-flash-debug.rst | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 4456151a..75db9a8a 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -698,6 +698,44 @@ determined by the imported subclasses of ``ZephyrBinaryRunner``. runner implementations are in other submodules, such as ``runners.nrfjprog``, ``runners.openocd``, etc. +Running Robot Framework tests: ``west robot`` +********************************************* + +.. tip:: Run ``west robot -h`` for additional help. + +Basics +====== + +Currently the command supports only one runner which is using ``renode-test``, +(essentially a wrapper for running Robot tests in Renode), but can be +easily extended by adding other runners. + +From a Zephyr build directory, to run a Robot test suite:: + + west robot --runner=renode-robot --testsuite path/to/testsuite.robot + +This will run all tests from testsuite.robot and print output provided +by Robot Framework. + +To pass additional parameters to Renode use ``--renode-robot-args`` switch. +For example to show Renode logs in addition to Robot Framework's output: + + west robot --runner=renode-robot --testsuite path/to/testsuite.robot --renode-robot-arg="--show-log" + +Runner-Specific Overrides +========================= + +To view all of the available options for the Robot runners your board +supports, as well as their usage information, use ``--context`` (or +``-H``):: + + west robot --runner=renode-robot --context + + +To view all available options "renode-test" runner supports, use:: + + west robot --runner=renode-robot --renode-robot-help + Simulating a board with: ``west simulate`` ****************************************** From 65bb96f4290bf7578f83914c24b9753cb6aeac2e Mon Sep 17 00:00:00 2001 From: Thomas Gagneret Date: Thu, 18 Jan 2024 17:31:46 +0100 Subject: [PATCH 185/226] scripts: zephyr_module: Add URL, version to SPDX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve the SPDX with the current values: - URL: extracted from `git remote`. If more than one remote, URL is not set. - Version: extracted from `git rev-parse` (commit id). - PURL and CPE for Zephyr: generated from URL and version. For zephyr, the tag is extracted, if present, and replace the commit id for the version field. Since official modules does not have tags, tags are not yet extracted for modules. To track vulnerabilities from modules dependencies, a new SBOM, `modules-deps.spdx` was created. It contains the `external-references` provided by the modules. It allows to easily track vulnerabilities from these external dependencies. Signed-off-by: Thomas Gagneret --- doc/develop/west/zephyr-cmds.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index f10c4abe..0ff913de 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -110,6 +110,8 @@ This generates the following SPDX bill-of-materials (BOM) documents in - :file:`app.spdx`: BOM for the application source files used for the build - :file:`zephyr.spdx`: BOM for the specific Zephyr source code files used for the build - :file:`build.spdx`: BOM for the built output files +- :file:`modules-deps.spdx`: BOM for modules dependencies. Check + :ref:`modules ` for more details. Each file in the bill-of-materials is scanned, so that its hashes (SHA256 and SHA1) can be recorded, along with any detected licenses if an From 843422a638692271ca10908045c6004fbb73ccc5 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 25 Jun 2024 14:44:12 +0200 Subject: [PATCH 186/226] doc: west: Clarify basic west terms Terms like the west workspace or even west projects and modules were not documented prominently enough, prompting users to ask for additional clarification. This patch attempts to resolve this by adding terms and explanation of concepts to the glossary and west doc pages. Fixes #67376. Signed-off-by: Carles Cufi --- doc/develop/west/basics.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/develop/west/basics.rst b/doc/develop/west/basics.rst index 2695a4f8..afedb33f 100644 --- a/doc/develop/west/basics.rst +++ b/doc/develop/west/basics.rst @@ -6,14 +6,20 @@ Basics This page introduces west's basic concepts and provides references to further reading. -West's built-in commands allow you to work with *projects* (Git -repositories) under a common *workspace* directory. +West's built-in commands allow you to work with :term:`projects ` +(Git repositories) under a common :term:`workspace ` directory. + +West works in the following manner: the ``west init`` command creates the +:term:`west workspace`, and clones the :term:`manifest repo `, while the ``west update`` command initially clones, and later updates, the +:term:`projects ` listed in the manifest in the workspace. Example workspace ***************** -If you've followed the upstream Zephyr getting started guide, your -workspace looks like this: +If you've followed the :ref:`getting_started`, your local +:term:`west workspace`, which in this case is the folder named +:file:`zephyrproject` as well as all its subfolders, looks like this: .. code-block:: none From e3628db16fdd93cd6c1125f27d8713db30833c59 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 6 Jul 2024 23:53:09 +0700 Subject: [PATCH 187/226] doc: fix typo in multiple directories before v3.7.0 release Utilize a code spell-checking tool to scan for and correct spelling errors in various files within the `doc` directory. Signed-off-by: Pisit Sawangvonganan --- doc/develop/west/build-flash-debug.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 75db9a8a..5cc4dd70 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -757,7 +757,7 @@ done by passing a command to Renode, using an argument provided by the runner: west simulate --runner=renode --renode-command start To pass an argument to Renode itself, for example to start Renode in console mode -intead of a separate window: +instead of a separate window: west simulate --runner=renode --renode-arg="--console" From 9f7fb3e8213ccbcaef9317c114ccdbe04bacb271 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Mon, 2 Sep 2024 12:58:35 +0200 Subject: [PATCH 188/226] tools: net-tools: place net-tools inside tools Updates references to the net-tools project to refer to the correct placement of net-tools under tools. Signed-off-by: Florian Grandel --- doc/develop/west/basics.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/develop/west/basics.rst b/doc/develop/west/basics.rst index afedb33f..342df36b 100644 --- a/doc/develop/west/basics.rst +++ b/doc/develop/west/basics.rst @@ -36,7 +36,8 @@ If you've followed the :ref:`getting_started`, your local ├── modules/ │ └── lib/ │ └── zcbor/ # .git/ project - ├── net-tools/ # .git/ project + ├── tools/ + │ └── net-tools/ # .git/ project └── [ ... other projects ...] .. _west-workspace: From 7de264368190ea90ae5e63397368d11bd02a2706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 10 Sep 2024 18:45:21 +0200 Subject: [PATCH 189/226] doc: sphinx-lint: fix unbalanced-inline-literals-delimiters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit used sphinx-lint to catch unbalanced inline literal markup. Signed-off-by: Benjamin Cabé --- doc/develop/west/build-flash-debug.rst | 2 +- doc/develop/west/west-apis.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 5cc4dd70..a7c19857 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -771,7 +771,7 @@ Runner-Specific Overrides ========================= To view all of the available options supported by the runners, as well -as their usage information, use ``--context`` (or``-H``):: +as their usage information, use ``--context`` (or ``-H``):: west simulate --runner=renode --context diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index 306cef81..e7eb623a 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -148,7 +148,7 @@ WestCommand .. method:: check_call(args, **kwargs) Runs ``subprocess.check_call(args, **kwargs)`` after - logging the call at Verbosity.DBG_MORE`` level. + logging the call at ``Verbosity.DBG_MORE`` level. .. versionchanged:: 1.2.0 The *cwd* keyword argument was replaced with a catch-all ``**kwargs``. From 98baf29c9388d50bc44ba80ff9a4fff6da8b193d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 10 Sep 2024 19:51:57 +0200 Subject: [PATCH 190/226] doc: sphinx-lint: fix bad usage of "default role" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes bad usage of single backticks in lieu of double backticks for rendering inline literals, or simple '*' for italics. When appropriate, a better construct than double backticks has been selected (ex. :file:, :kconfig:option:, :c:func:, ...), or proper :ref: have been used if the original intention was to have a link. Signed-off-by: Benjamin Cabé --- doc/develop/west/sign.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index ef98631b..355682c0 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -116,7 +116,7 @@ for all images, for example: west build -b -DSIGNING_SCRIPT= The zephyr property method is achieved by adjusting the ``SIGNING_SCRIPT`` property -on the `zephyr_property_target`, ideally from by a module by using: +on the ``zephyr_property_target``, ideally from by a module by using: .. code-block:: cmake From 980623b3246449dce1ac10882b1cd4168d96d04e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 11 Sep 2024 22:26:10 +0200 Subject: [PATCH 191/226] samples: hello_world: use zephyr:code-sample directive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds missing code-sample directive to the Hello World sample in preparation for upcoming changes to the Zephyr documentation that will be leveraging the provided description and metadata. Signed-off-by: Benjamin Cabé --- doc/develop/west/build-flash-debug.rst | 6 +++--- doc/develop/west/sign.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index a7c19857..36a4d5dd 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -145,7 +145,7 @@ Setting the Build System Target To specify the build system target to run, use ``--target`` (or ``-t``). For example, on host platforms with QEMU, you can use the ``run`` target to -build and run the :ref:`hello_world` sample for the emulated :ref:`qemu_x86 +build and run the :zephyr:code-sample:`hello_world` sample for the emulated :ref:`qemu_x86 ` board in one command:: west build -b qemu_x86 -t run samples/hello_world @@ -349,7 +349,7 @@ The ``-o`` option is described further in the previous section. Build a single domain --------------------- -In a multi-domain build with :ref:`hello_world` and `MCUboot`_, you can use +In a multi-domain build with :zephyr:code-sample:`hello_world` and `MCUboot`_, you can use ``--domain hello_world`` to only build this domain:: west build --sysbuild --domain hello_world @@ -543,7 +543,7 @@ will flash all domains in the order defined by sysbuild. It is possible to flash the image from a single domain in a multi-domain project by using ``--domain``. -For example, in a multi-domain build with :ref:`hello_world` and +For example, in a multi-domain build with :zephyr:code-sample:`hello_world` and `MCUboot`_, you can use the ``--domain hello_world`` domain to only flash only the image from this domain:: diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 355682c0..7de7bf7d 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -22,7 +22,7 @@ If you use this feature, you don't need to run ``west sign`` yourself; the build system will do it for you. Here is an example workflow, which builds and flashes MCUboot, as well as the -:ref:`hello_world` application for chain-loading by MCUboot. Run these commands +:zephyr:code-sample:`hello_world` application for chain-loading by MCUboot. Run these commands from the :file:`zephyrproject` workspace you created in the :ref:`getting_started`. From 9f2fb6e4194b1c39e1ac0208fa132e9dd7d1dc15 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 26 Sep 2024 08:04:54 +0100 Subject: [PATCH 192/226] doc: build: Add signing page Adds a signing page under build, which contains information on how to sign images from the build system, this removes the old details for using west sign with imgtool from the west sign page Signed-off-by: Jamie McCrae --- doc/develop/west/sign.rst | 127 -------------------------------------- 1 file changed, 127 deletions(-) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 7de7bf7d..9b17bf02 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -9,133 +9,6 @@ external tool. In some configurations, ``west sign`` is also used to invoke an external, post-processing tool that "stitches" the final components of the image together. Run ``west sign -h`` for command line help. -MCUboot / imgtool -***************** - -The Zephyr build system has special support for signing binaries for use with -the `MCUboot`_ bootloader using the `imgtool`_ program provided by its -developers. You can both build and sign this type of application binary in one -step by setting some Kconfig options. If you do, ``west flash`` will use the -signed binaries. - -If you use this feature, you don't need to run ``west sign`` yourself; the -build system will do it for you. - -Here is an example workflow, which builds and flashes MCUboot, as well as the -:zephyr:code-sample:`hello_world` application for chain-loading by MCUboot. Run these commands -from the :file:`zephyrproject` workspace you created in the -:ref:`getting_started`. - -.. code-block:: console - - west build -b YOUR_BOARD bootloader/mcuboot/boot/zephyr -d build-mcuboot - west build -b YOUR_BOARD zephyr/samples/hello_world -d build-hello-signed -- \ - -DCONFIG_BOOTLOADER_MCUBOOT=y \ - -DCONFIG_MCUBOOT_SIGNATURE_KEY_FILE=\"bootloader/mcuboot/root-rsa-2048.pem\" - - west flash -d build-mcuboot - west flash -d build-hello-signed - -Notes on the above commands: - -- ``YOUR_BOARD`` should be changed to match your board -- The ``CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`` value is the insecure default - provided and used by MCUboot for development and testing -- You can change the ``hello_world`` application directory to any other - application that can be loaded by MCUboot, such as the :zephyr:code-sample:`smp-svr` sample. - -For more information on these and other related configuration options, see: - -- :kconfig:option:`CONFIG_BOOTLOADER_MCUBOOT`: build the application for loading by - MCUboot -- :kconfig:option:`CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`: the key file to use with ``west - sign``. If you have your own key, change this appropriately -- :kconfig:option:`CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS`: optional additional command line - arguments for ``imgtool`` -- :kconfig:option:`CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE`: also generate a confirmed - image, which may be more useful for flashing in production environments than - the OTA-able default image -- On Windows, if you get "Access denied" issues, the recommended fix is - to run ``pip3 install imgtool``, then retry with a pristine build directory. - -If your ``west flash`` :ref:`runner ` uses an image format -supported by imgtool, you should see something like this on your device's -serial console when you run ``west flash -d build-mcuboot``: - -.. code-block:: none - - *** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 *** - [00:00:00.004,669] mcuboot: Starting bootloader - [00:00:00.011,169] mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3 - [00:00:00.021,636] mcuboot: Boot source: none - [00:00:00.027,313] mcuboot: Failed reading image headers; Image=0 - [00:00:00.035,064] mcuboot: Unable to find bootable image - -Then, you should see something like this when you run ``west flash -d -build-hello-signed``: - -.. code-block:: none - - *** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 *** - [00:00:00.004,669] mcuboot: Starting bootloader - [00:00:00.011,169] mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3 - [00:00:00.021,636] mcuboot: Boot source: none - [00:00:00.027,374] mcuboot: Swap type: none - [00:00:00.115,142] mcuboot: Bootloader chainload address offset: 0xc000 - [00:00:00.123,168] mcuboot: Jumping to the first image slot - *** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 *** - Hello World! nrf52840dk_nrf52840 - -Whether ``west flash`` supports this feature depends on your runner. The -``nrfjprog`` and ``pyocd`` runners work with the above flow. If your runner -does not support this flow and you would like it to, please send a patch or -file an issue for adding support. - -.. _west-extending-signing: - -Extending signing externally -**************************** - -The signing script used when running ``west flash`` can be extended or replaced -to change features or introduce different signing mechanisms. By default with -MCUboot enabled, signing is setup by the :file:`cmake/mcuboot.cmake` file in -Zephyr which adds extra post build commands for generating the signed images. -The file used for signing can be replaced from a sysbuild scope (if being used) -or from a zephyr/zephyr module scope, the priority of which is: - -* Sysbuild -* Zephyr property -* Default MCUboot script (if enabled) - -From sysbuild, ``-D_SIGNING_SCRIPT`` can be used to set a signing script -for a specific image or ``-DSIGNING_SCRIPT`` can be used to set a signing script -for all images, for example: - -.. code-block:: console - - west build -b -DSIGNING_SCRIPT= - -The zephyr property method is achieved by adjusting the ``SIGNING_SCRIPT`` property -on the ``zephyr_property_target``, ideally from by a module by using: - -.. code-block:: cmake - - if(CONFIG_BOOTLOADER_MCUBOOT) - set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/custom_signing.cmake) - endif() - -This will include the custom signing CMake file instead of the default Zephyr -one when projects are built with MCUboot signing support enabled. The base -Zephyr MCUboot signing file can be used as a reference for creating a new -signing system or extending the default behaviour. - -.. _MCUboot: - https://mcuboot.com/ - -.. _imgtool: - https://pypi.org/project/imgtool/ - - rimage ****** From 6054d9956e46da995de4ce5448e123a4c416c38e Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Wed, 20 Dec 2023 18:03:59 +0200 Subject: [PATCH 193/226] west: bindesc: Added get_offset command Add `west bindesc get_offset` command to print the offset of the descriptors inside the given image. Signed-off-by: Yonatan Schachter --- doc/develop/west/zephyr-cmds.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 0ff913de..0c665c7f 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -215,3 +215,7 @@ You can dump all of the descriptors in an image using:: You can list all known standard descriptor names using:: west bindesc list + +You can print the offset of the descriptors inside the image using:: + + west bindesc get_offset From 515dcf87e27bcfdc5e58a45c9729c643447f131d Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 18 Oct 2024 18:32:15 +0000 Subject: [PATCH 194/226] doc: sign: minor rimage update following imgtool removal Fixes commit 9f2fb6e4194b ("doc: build: Add signing page") that removed the `imgtool` section from the `sign.rst` page. rimage configuration was designed in a very different way from imgtool configuration. The rimage doc section was following the imgtool doc section and constrating the two approaches. Now that the previous imgtool doc section has just been removed, some words like "different" and "instead" don't make sense anymore. Drop them. Signed-off-by: Marc Herbert --- doc/develop/west/sign.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 9b17bf02..21eeac87 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -12,8 +12,8 @@ the image together. Run ``west sign -h`` for command line help. rimage ****** -rimage configuration uses a different approach that does not rely on Kconfig or CMake -but on :ref:`west config` instead, similar to +rimage configuration uses an approach that does not rely on Kconfig or CMake +but on :ref:`west config`, similar to :ref:`west-building-cmake-config`. Signing involves a number of "wrapper" scripts stacked on top of each other: ``west @@ -31,8 +31,8 @@ build logs can be unreliable: it may produce different results because of subtle environment differences. Last and worst: new signing feature and options are impossible to use until more boilerplate code has been added in each layer. -To avoid these issues, ``rimage`` parameters can bet set in ``west config`` -instead. Here's a ``workspace/.west/config`` example: +To avoid these issues, ``rimage`` parameters can bet set in ``west config``. +Here's a ``workspace/.west/config`` example: .. code-block:: ini From 5689990825b9419989d11b275c37c2129c6923ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 21 Oct 2024 15:24:59 +0200 Subject: [PATCH 195/226] boards: qemu: adopt new zephyr:board directive and role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This updates the documentation of all the Qemu boards to use the new `zephyr:board::` directive. Signed-off-by: Benjamin Cabé --- doc/develop/west/build-flash-debug.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 36a4d5dd..c45a4551 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -145,8 +145,8 @@ Setting the Build System Target To specify the build system target to run, use ``--target`` (or ``-t``). For example, on host platforms with QEMU, you can use the ``run`` target to -build and run the :zephyr:code-sample:`hello_world` sample for the emulated :ref:`qemu_x86 -` board in one command:: +build and run the :zephyr:code-sample:`hello_world` sample for the emulated +:zephyr:board:`qemu_x86 ` board in one command:: west build -b qemu_x86 -t run samples/hello_world From 7df66492b5e3d3ed2b5d25bc71d37f2f299e75b6 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 17 Jul 2024 22:25:39 +0200 Subject: [PATCH 196/226] doc: develop: west: Add alias documentation Add documentation and examples for west aliases. Signed-off-by: Pieter De Gendt --- doc/develop/west/alias.rst | 61 +++++++++++++++++++++++++++++++++++++ doc/develop/west/config.rst | 3 ++ doc/develop/west/index.rst | 1 + 3 files changed, 65 insertions(+) create mode 100644 doc/develop/west/alias.rst diff --git a/doc/develop/west/alias.rst b/doc/develop/west/alias.rst new file mode 100644 index 00000000..5e55652e --- /dev/null +++ b/doc/develop/west/alias.rst @@ -0,0 +1,61 @@ +.. _west-aliases: + +West aliases +############ + +West allows to add alias commands to the local, global or system configuration files. +These aliases make it easy to add shortcuts for frequently used, or hard to memorize +commands for ease of development. + +Similar to how ``git`` aliases work, the alias command is replaced with the alias' +full text and parsed as a new shell argument list (using the Python function +`shlex.split()`_ internally to split the value). This enables adding argument +parameters as they were passed to the original command. Spaces are considered +argument separators; use proper escaping if arguments shouldn't be split. + +.. _shlex.split(): https://docs.python.org/3/library/shlex.html#shlex.split + +To add a new alias simply call the ``west config`` command: + +.. code-block:: shell + + west config alias.mylist "list -f '{name} {revision}'" + +To list aliases, use :samp:`west help {some_alias}`. + +Recursive aliases are allowed as an alias command can contain other aliases, effectively +building more complex but easy-to-remember commands. + +It is possible to override an existing command, for example to pass default arguments: + +.. code-block:: shell + + west config alias.update "update -o=--depth=1 -n" + +.. warning:: + + Overriding/shadowing other or built-in commands is an advanced use case, it can lead to + strange side-effects and should be done with great care. + +Examples +-------- + +Add ``west run`` and ``west menuconfig`` shortcuts to your global configuration to +call ``west build`` with the corresponding CMake targets: + +.. code-block:: shell + + west config --global alias.run "build --pristine=never --target run" + west config --global alias.menuconfig "build --pristine=never --target menuconfig" + +Create an alias for the sample you are actively developing with additional options: + +.. code-block:: shell + + west config alias.sample "build -b native_sim samples/hello_world -t run -- -DCONFIG_ASSERT=y" + +Override ``west update`` to check a local cache: + +.. code-block:: shell + + west config alias.update "update --path-cache $HOME/.cache/zephyrproject" diff --git a/doc/develop/west/config.rst b/doc/develop/west/config.rst index eae6c7e4..51420abb 100644 --- a/doc/develop/west/config.rst +++ b/doc/develop/west/config.rst @@ -130,6 +130,9 @@ commands are documented in the pages for those commands. * - Option - Description + * - :samp:`alias.{ALIAS}` + - String. If non-empty the ```` can be used as a west command. + See :ref:`west-aliases`. * - ``color.ui`` - Boolean. If ``true`` (the default), then west output is colorized when stdout is a terminal. diff --git a/doc/develop/west/index.rst b/doc/develop/west/index.rst index 7b5fd6b2..ce738179 100644 --- a/doc/develop/west/index.rst +++ b/doc/develop/west/index.rst @@ -37,6 +37,7 @@ each command. workspaces.rst manifest.rst config.rst + alias.rst extensions.rst build-flash-debug.rst sign.rst From bb021e13c29311076a4b016d6ad05706eaffd5d7 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Sun, 29 Sep 2024 16:19:07 +0200 Subject: [PATCH 197/226] doc: develop: west: Remove deprecated west.log The global state west.log is deprecated, replace with WestCommand logging. Signed-off-by: Pieter De Gendt --- doc/develop/west/extensions.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/develop/west/extensions.rst b/doc/develop/west/extensions.rst index 520e0ec4..923d8661 100644 --- a/doc/develop/west/extensions.rst +++ b/doc/develop/west/extensions.rst @@ -87,7 +87,6 @@ details on the west APIs you can use, see :ref:`west-apis`. from textwrap import dedent # just for nicer code indentation from west.commands import WestCommand # your extension must subclass this - from west import log # use this for user output class MyCommand(WestCommand): @@ -125,8 +124,8 @@ details on the west APIs you can use, see :ref:`west-apis`. # $ west my-command-name -o FOO BAR # --optional is FOO # required is BAR - log.inf('--optional is', args.optional) - log.inf('required is', args.required) + self.inf('--optional is', args.optional) + self.inf('required is', args.required) You can ignore the second argument to ``do_run()`` (``unknown_args`` above), as ``WestCommand`` will reject unknown arguments by default. If you want to be From 1f960cc290a7a2701d3a887291ff0fd1fede80d3 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 19 Dec 2024 17:18:22 +0100 Subject: [PATCH 198/226] doc: develop: Add external runners for modules information Add an example for the `runners` section in the zephyr/module.yml file, and a paragraph to the west "flash and debug runners" section. Signed-off-by: Pieter De Gendt --- doc/develop/west/build-flash-debug.rst | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index c45a4551..2b7dd3ec 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -779,6 +779,19 @@ To view all available options Renode supports, use:: west simulate --runner=renode --renode-help +Out of tree runners +******************* + +:ref:`Zephyr modules ` can have external runners discovered by adding python +files in their :ref:`module.yml `. Create an external runner class by +inheriting from ``ZephyrBinaryRunner`` and implement all abstract methods. + +.. note:: + + Support for custom out-of-tree runners makes the ``runners.core`` module part of + the public API and backwards incompatible changes need to undergo the + :ref:`deprecation process `. + Hacking ******* @@ -786,11 +799,6 @@ This section documents the ``runners.core`` module used by the flash and debug commands. This is the core abstraction used to implement support for these features. -.. warning:: - - These APIs are provided for reference, but they are more "shared code" used - to implement multiple extension commands than a stable API. - Developers can add support for new ways to flash and debug Zephyr programs by implementing additional runners. To get this support into upstream Zephyr, the runner should be added into a new or existing ``runners`` module, and imported From 4851645fdcec851d61532cb31ff66dd26f79d539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Tue, 21 Jan 2025 09:52:46 -0800 Subject: [PATCH 199/226] doc: the west workspace topdir is not a git repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a design decision that the west workspace "topdir" (that is, the top level directory containing the .west directory), is not itself a git repository. This exists to give us some breathing room to make changes to the workspace which would otherwise potentially cause breakage if the entire workspace is in .git. While this has always been the case, I'm documenting this now because I reviewed a PR today that flipped my bit from "this is a question to answer on a case by case basis" to "this is a frequently enough asked question that I want to be able to link people to the answer": https://github.com/zephyrproject-rtos/zephyr/pull/84305 We can debate the wisdom of this design decision (and, informally, I've always tried to avoid breaking these setups), but IMO it's too late to try to change this in west. Make it explicit in the docs that you're on your own if you try this. Signed-off-by: Martí Bolívar --- doc/develop/west/workspaces.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doc/develop/west/workspaces.rst b/doc/develop/west/workspaces.rst index 5c182658..d3dadc2b 100644 --- a/doc/develop/west/workspaces.rst +++ b/doc/develop/west/workspaces.rst @@ -321,3 +321,25 @@ v2.5.0 and its modules, then add the ``app1`` and ``app2`` projects: You can also do this "by hand" by copy/pasting :file:`zephyr/west.yml` as shown :ref:`above ` for the T2 topology, with the same caveats. + +.. _workspace-as-git-repo: + +Not supported: workspace topdir as .git repository +************************************************** + +Some users have asked for support making the workspace :ref:`topdir +` a git repository, like this example: + +.. code-block:: none + + my-workspace/ # workspace topdir + ├── .git/ # puts the entire workspace in a git repository + ├── .west/ # marks the location of the topdir + └── [ ... other projects ...] + +This is **not** an officially supported topology. As a design decision, west +assumes that the workspace topdir itself is not a git repository. + +You may be able to make something like this "work" for yourself and your own +goals. However, future versions of west might contain changes which can "break" +your setup. From b5b332ef9cfe76d0f52217915bd07337170d81ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 19 Feb 2025 00:10:33 -0800 Subject: [PATCH 200/226] doc: document "west gtags" command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document this command's existence, provide basic usage, and describe the locations of resources where additional help etc. should be found. Signed-off-by: Martí Bolívar --- doc/develop/west/zephyr-cmds.rst | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 0c665c7f..b4ef9532 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -219,3 +219,52 @@ You can list all known standard descriptor names using:: You can print the offset of the descriptors inside the image using:: west bindesc get_offset + +Indexing the sources with GNU Global: ``west gtags`` +**************************************************** + +.. important:: You must install the ``gtags`` and ``global`` programs provided + by `GNU Global`_ to use this command. + +The ``west gtags`` command lets you create a GNU Global tags file for the entire +west workspace:: + + west gtags + +.. _GNU Global: https://www.gnu.org/software/global/ + +This will create a tags file named ``GTAGS`` in the workspace :ref:`topdir +` (it will also create other Global-related metadata files +named ``GPATH`` and ``GRTAGS`` in the same place). + +You can then run the ``global`` command anywhere inside the +workspace to search for symbol locations using this tags file. + +For example, to search for definitions of the ``arch_system_halt()`` function, +starting from the ``zephyr/drivers`` directory:: + + $ cd zephyr/drivers + $ global -x arch_system_halt + arch_system_halt 65 ../arch/arc/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) + arch_system_halt 455 ../arch/arm64/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) + arch_system_halt 137 ../arch/nios2/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) + arch_system_halt 18 ../arch/posix/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) + arch_system_halt 17 ../arch/x86/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) + arch_system_halt 126 ../arch/xtensa/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) + arch_system_halt 21 ../kernel/fatal.c FUNC_NORETURN __weak void arch_system_halt(unsigned int reason) + +This prints the search symbol, the line it is defined on, a relative path to +the file it is defined in, and the line itself, for all places where the symbol +is defined. + +Additional tips: + +- This can also be useful to search for vendor HAL function definitions. + +- See the ``global`` command's manual page for more information on how to use + this tool. + +- You should run ``global``, **not** ``west global``. There is no need for a + separate ``west global`` command since ``global`` already searches for the + ``GTAGS`` file starting from your current working directory. This is why you + need to run ``global`` from inside the workspace. From 8c0e42f405bf97780d9538f5c8a82af70e35fc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tais=20Hjortsh=C3=B8j?= Date: Sun, 13 Apr 2025 00:46:22 +0200 Subject: [PATCH 201/226] scripts: west_commands: Add powershell autocompletion (west -b) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows powershell can by default not autocomplete known boards when tapping which can cause frustration when you can't quite remember the exact name or you don't want to type it out. west build .\path\to\application\ -p -b stm will search for available board including 'stm' in their name. Signed-off-by: Tais Hjortshøj --- doc/develop/west/install.rst | 18 ++++++++++++++++++ doc/develop/west/zephyr-cmds.rst | 1 + 2 files changed, 19 insertions(+) diff --git a/doc/develop/west/install.rst b/doc/develop/west/install.rst index 5ac0f6ef..cb207bf3 100644 --- a/doc/develop/west/install.rst +++ b/doc/develop/west/install.rst @@ -53,6 +53,7 @@ West currently supports shell completion in the following shells: * bash * zsh * fish +* powershell (board qualifiers only) In order to enable shell completion, you will need to obtain the corresponding completion script and have it sourced. @@ -102,5 +103,22 @@ Using the completion scripts: west completion fish > $HOME/.config/fish/completions/west.fish + .. group-tab:: powershell + + *One-time setup*: + + .. code-block:: powershell + + west completion powershell | Out-String | Invoke-Expression + + *Permanent setup*: + + .. code-block:: powershell + + Set-ExecutionPolicy RemoteSigned -Scope CurrentUser + New-item -type file -force $PROFILE + west completion powershell > $HOME/west-completion.ps1 + (Add-Content -Path $PROFILE -Value ". '{$HOME/west-completion.ps1}'") + .. _PyPI: https://pypi.org/project/west/ diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index b4ef9532..1afd5f9b 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -40,6 +40,7 @@ It currently supports the following shells: - bash - zsh - fish +- powershell (board qualifiers only) Additional instructions are available in the command's help:: From 3503e5dbbf4393ebea327b95c895ad1bfcae657b Mon Sep 17 00:00:00 2001 From: Tobias Meyer Date: Wed, 16 Apr 2025 16:42:40 +0200 Subject: [PATCH 202/226] doc: sbom cmd more detail for build_dir when following the example it was not clear that BUILD_DIR needs to point to application for sysbuild builds Signed-off-by: Tobias Meyer --- doc/develop/west/zephyr-cmds.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 1afd5f9b..0a0a9ed1 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -105,6 +105,18 @@ To use this command: west spdx -d BUILD_DIR +.. note:: + + When building with :ref:`sysbuild`, make sure you target the actual application + which you want to generate the SBOM for. For example, if the application is + named ``hello_world``: + + .. code-block:: bash + + west spdx --init -d BUILD_DIR/hello_world + west build -d BUILD_DIR/hello_world + west spdx -d BUILD_DIR/hello_world + This generates the following SPDX bill-of-materials (BOM) documents in :file:`BUILD_DIR/spdx/`: From fd89fcf7cfdd2c2eb30738e1e876a5c037db225c Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Fri, 9 May 2025 12:19:23 -0400 Subject: [PATCH 203/226] doc: west: add documentation for west patch Add documentation for the `west patch` command. Signed-off-by: Chris Friedt --- doc/develop/west/zephyr-cmds.rst | 120 +++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 0a0a9ed1..e40093c3 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -281,3 +281,123 @@ Additional tips: separate ``west global`` command since ``global`` already searches for the ``GTAGS`` file starting from your current working directory. This is why you need to run ``global`` from inside the workspace. + +.. _west-patch: + +Working with patches: ``west patch`` +************************************ + +The ``patch`` command allows users to apply patches to Zephyr or Zephyr modules +in a controlled manner that makes automation and tracking easier for external applications that +use the :ref:`T2 star topology `. The :ref:`patches.yml ` file stores +metadata about patch files and fills-in the gaps between official Zephyr releases, so that users +can easily see the status of any upstreaming efforts, and determine which patches to drop before +upgrading to the next Zephyr release. + +There are several sub-commands available to manage patches for Zephyr or other modules in the +workspace: + +* ``apply``: apply patches listed in ``patches.yml`` +* ``clean``: remove all patches that have been applied, and reset to the manifest checkout state +* ``list``: list all patches in ``patches.yml`` +* ``gh-fetch``: fetch patches from a GitHub pull request + +.. code-block:: none + + west-workspace/ + └── application/ + ... + ├── west.yml + └── zephyr + ├── module.yml + ├── patches + │ ├── bootloader + │ │ └── mcuboot + │ │ └── my-tweak-for-mcuboot.patch + │ └── zephyr + │ └── my-zephyr-change.patch + └── patches.yml + +In this example, the :ref:`west manifest ` file, ``west.yml``, would pin to a +specific Zephyr revision (e.g. ``v4.1.0``) and apply patches against that revision of Zephyr and +the specific revisions of other modules used in the application. However, this application needs +two changes in order to meet requirements; one for Zephyr and another for MCUBoot. + +.. _patches-yml: + +.. code-block:: yaml + + patches: + - path: zephyr/my-zephyr-change.patch + sha256sum: c676cd376a4d19dc95ac4e44e179c253853d422b758688a583bb55c3c9137035 + module: zephyr + author: Obi-Wan Kenobi + email: obiwan@jedi.org + date: 2025-05-04 + upstreamable: false + comments: | + An application-specific change we need for Zephyr. + - path: bootloader/mcuboot/my-tweak-for-mcuboot.patch + sha256sum: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + module: mcuboot + author: Darth Sidious + email: sidious@sith.org + date: 2025-05-04 + merge-pr: https://github.com/zephyrproject-rtos/zephyr/pull/ + issue: https://github.com/zephyrproject-rtos/zephyr/issues/ + merge-status: true + merge-commit: 1234567890abcdef1234567890abcdef12345678 + merge-date: 2025-05-06 + apply-command: git apply + comments: | + A change to mcuboot that has been merged already. We can remove this + patch when we are ready to upgrade to the next Zephyr release. + +Patches can easily be applied in an automated manner. For example: + +.. code-block:: bash + + west init -m + cd + west update + west patch apply + +When it is time to update to a newer version of Zephyr, the ``west.yml`` file can be updated to +point at the next Zephyr release, e.g. ``v4.2.0``. Patches that are no longer needed, like +``my-tweak-for-mcuboot.patch`` in the example above, can be removed from ``patches.yml`` and from +the external application repository, and then the following commands can be run. + +.. code-block:: bash + + west patch clean + west update + west patch apply --roll-back # roll-back all patches if one does not apply cleanly + +If a patch needs to be reworked, remember to update the ``patches.yml`` file with the new SHA256 +checksum. + +.. code-block:: bash + + sha256sum zephyr/patches/zephyr/my-zephyr-change.patch + 7d57ca78d5214f422172cc47fed9d0faa6d97a0796c02485bff0bf29455765e9 + +It is also possible to use ``west patch gh-fetch`` to fetch patches from a GitHub pull request and +automatically create or update the ``patches.yml`` file. This can be useful when the author already +has a number of changes captured in existing upstream pull requests. + +.. code-block:: bash + + west patch gh-fetch --owner zephyrproject-rtos --repo zephyr --pull-request \ + --module zephyr --split-commits + +The above command will create the directory and file structure below, which includes patches for +each individual commit associated with the given pull request. + +.. code-block:: none + + zephyr + ├── patches + │ ├── first-commit-from-pr.patch + │ ├── second-commit-from-pr.patch + │ └── third-commit-from-pr.patch + └── patches.yml From 8138d6031d7914e020383258f07076b26bf07f9a Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 15 May 2025 15:36:52 +0200 Subject: [PATCH 204/226] doc: develop: west: Update release notes Add release notes for v1.3.0 and v1.4.0. Signed-off-by: Pieter De Gendt --- doc/develop/west/release-notes.rst | 78 ++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 951cc4c3..6252be9d 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -3,6 +3,84 @@ West Release Notes ################## +v1.4.0 +****** + +Changes: + +- Allow appending data to configuration strings. + To append to a value for ````, type: ``west config -a ``. + +- Add ``--untracked`` argument option to ``west manifest``. + Run ``west manifest --untracked`` in a workspace to print all files and + directories that are not tracked or managed by west. + +- Add ``--inactive`` argument option to ``west list`` to support printing inactive projects. + +- Support ``--active-only`` argument option for the ``west manifest --resolve`` and + ``west manidest --freeze`` commands. + This allows freezing workspaces with active project or group filters. + +API changes: + +- ``west.manifest.Manifest`` methods ``as_dict()``, ``as_frozen_dict()``, ``as_yaml()`` and + ``as_frozen_yaml()`` now have an optional ``active_only`` argument (defaults to ``False``) + to return an object containing all projects or only the active ones. + +v1.3.0 +****** + +Major changes: + +- Added support for :ref:`west-aliases` commands. + +- Adopt the `pyproject TOML specification`_ for packaging. + +.. _pyproject TOML specification: + https://packaging.python.org/en/latest/specifications/pyproject-toml/ + +Other changes: + +- Add cache support for submodules. + +- Decode manifest files as UTF-8 by default. + +- Pass unknown arguments for ``west diff`` and ``west status`` to underlying ``git`` commands. + +- Added ``--manifest`` argument to ``west diff`` to allow comparing + the current workspace to the manifest revisions. + +- Environment variables can be used with west forall + The following are defined: + + - ``WEST_PROJECT_NAME`` + - ``WEST_PROJECT_PATH`` + - ``WEST_PROJECT_ABSPATH`` + - ``WEST_PROJECT_REVISION`` + - ``WEST_PROJECT_URL`` + - ``WEST_PROJECT_REMOTE`` + +- Added support for early argument ``-q/--quiet`` to reduce verbosity. + +- Added ``-o/--clone-opt`` argument to ``west init`` to pass to ``git clone``. + +- Support Python 3.13 and drop support for Python 3.8. + +- Prevent manifests from having projects in the ``.west`` directory. + +- Add NTFS workarounds and ``--rename-delay`` for ``west init``. + +- Print a stack trace when calling die in debug ``-vvv``. + +Bug fixes: + +- Use ``'backslashreplace'`` not to crash on malformed UTF from subprocess. + +- Fix handling in ``west diff`` for repositories with merge conflicts. + Additionally improve error printing and handle ``git diff`` return codes. + +- Fix ``--freeze`` and ``--resolve`` for the ``west manifest`` command when git submodules are used. + v1.2.0 ****** From 6316820e4054a234c47fa376cb7bb899e36faf3a Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 16 May 2025 09:08:49 +0200 Subject: [PATCH 205/226] doc: develop: west: Update west API for v1.4.0 Update the west API documentation for the added active_only arguments to as_dict/as_frozen_dict/as_yaml/as_frozen_yaml. Signed-off-by: Pieter De Gendt --- doc/develop/west/west-apis.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index e7eb623a..04129ee9 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -409,11 +409,19 @@ Manifest and sub-objects Additional methods: .. automethod:: as_dict + .. versionadded:: 1.4.0 + The *active_only* argument. .. versionadded:: 0.7.0 .. automethod:: as_frozen_dict + .. versionadded:: 1.4.0 + The *active_only* argument. .. automethod:: as_yaml + .. versionadded:: 1.4.0 + The *active_only* argument. .. versionadded:: 0.7.0 .. automethod:: as_frozen_yaml + .. versionadded:: 1.4.0 + The *active_only* argument. .. versionadded:: 0.7.0 .. automethod:: is_active .. versionadded:: 0.9.0 From af53eee043ee328176ed5846bc3830d9271d6d96 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Fri, 23 May 2025 19:42:05 +0200 Subject: [PATCH 206/226] doc: west: releases: Fix typo s/manidest/manifest. Signed-off-by: Carles Cufi --- doc/develop/west/release-notes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 6252be9d..861406cd 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -18,7 +18,7 @@ Changes: - Add ``--inactive`` argument option to ``west list`` to support printing inactive projects. - Support ``--active-only`` argument option for the ``west manifest --resolve`` and - ``west manidest --freeze`` commands. + ``west manifest --freeze`` commands. This allows freezing workspaces with active project or group filters. API changes: From b7bb1c9539e58182e8e959caf8bb0c974bc9d937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 28 May 2025 17:13:27 +0200 Subject: [PATCH 207/226] west: spdx: allow to generate for different SPDX versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When support for SPDX 2.3 was added, it effectively dropped support for SPDX 2.2, which in retrospect was a bad idea since SPDX 2.2 is the version that is the current ISO/IEC standard. This commit adds a `--spdx-version` option to the `west spdx` command so that users can generate SPDX 2.2 documents if they want. Default is 2.3 given that's effectively what shipped for a few releases now, including latest LTS. Signed-off-by: Benjamin Cabé --- doc/develop/west/zephyr-cmds.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index e40093c3..100e05f9 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -75,7 +75,7 @@ See :zephyr_file:`share/zephyr-package/cmake` for details. Software bill of materials: ``west spdx`` ***************************************** -This command generates SPDX 2.3 tag-value documents, creating relationships +This command generates SPDX 2.2 or 2.3 tag-value documents, creating relationships from source files to the corresponding generated build files. ``SPDX-License-Identifier`` comments in source files are scanned and filled into the SPDX documents. @@ -105,6 +105,12 @@ To use this command: west spdx -d BUILD_DIR + By default, this generates SPDX 2.3 documents. To generate SPDX 2.2 documents instead: + + .. code-block:: bash + + west spdx -d BUILD_DIR --spdx-version 2.2 + .. note:: When building with :ref:`sysbuild`, make sure you target the actual application @@ -144,6 +150,10 @@ source files that are compiled to generate the built library files. - ``-s SPDX_DIR``: specifies an alternate directory where the SPDX documents should be written instead of :file:`BUILD_DIR/spdx/`. +- ``--spdx-version {2.2,2.3}``: specifies which SPDX specification version to use. + Defaults to ``2.3``. SPDX 2.3 includes additional fields like ``PrimaryPackagePurpose`` + that are not available in SPDX 2.2. + - ``--analyze-includes``: in addition to recording the compiled source code files (e.g. ``.c``, ``.S``) in the bills-of-materials, also attempt to determine the specific header files that are included for each ``.c`` file. From 262b30fe00aab068f369a3037ac09df076490163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 17 Jun 2025 17:26:20 +0200 Subject: [PATCH 208/226] doc: develop: west: document spdx not being supported for native_sim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generating SPDX SBOMs for the ``native_sim`` platform has propably never worked, but at least now it will be documented. Signed-off-by: Benjamin Cabé --- doc/develop/west/zephyr-cmds.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 100e05f9..12048783 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -165,6 +165,10 @@ source files that are compiled to generate the built library files. - ``--include-sdk``: with ``--analyze-includes``, also create a fourth SPDX document, :file:`sdk.spdx`, which lists header files included from the SDK. +.. warning:: + + The generation of SBOM documents for the ``native_sim`` platform is currently not supported. + .. _SPDX specification clause 6: https://spdx.github.io/spdx-spec/v2.2.2/document-creation-information/ From 41d8774fe329c3ac8da4f5b7e12efeb372beb832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 11 Jun 2025 14:29:57 +0200 Subject: [PATCH 209/226] scripts: west: spdx: extract copyright info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit use REUSE to extract copyright text from source files and include in SBOM documents Signed-off-by: Benjamin Cabé --- doc/develop/west/zephyr-cmds.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 12048783..ee5e8b28 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -136,6 +136,13 @@ Each file in the bill-of-materials is scanned, so that its hashes (SHA256 and SHA1) can be recorded, along with any detected licenses if an ``SPDX-License-Identifier`` comment appears in the file. +Copyright notices are extracted using the third-party :command:`reuse` tool from the REUSE group. +When found, these notices are added to SPDX documents as ``FileCopyrightText`` fields. + +.. note:: + Copyright extraction uses heuristics that may not capture complete notice text, so + ``FileCopyrightText`` content is best-effort. This aligns with SPDX specification recommendations. + SPDX Relationships are created to indicate dependencies between CMake build targets, build targets that are linked together, and source files that are compiled to generate the built library files. From 59dd49cd25d2ea88c9b6d57383070d800dc1ba40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Wed, 25 Jun 2025 14:11:51 +0200 Subject: [PATCH 210/226] doc: sign: Describe usage of silabs_commander tool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the relevant documentation for the silabs_commander runner. Co-developed-by: Aasim Shaik Signed-off-by: Aasim Shaik Signed-off-by: Jérôme Pouiller --- doc/develop/west/sign.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 21eeac87..b2d85367 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -58,3 +58,23 @@ both are used, the command-line arguments go last. .. _rimage: https://github.com/thesofproject/rimage + + +silabs_commander +**************** + +The ``silabs_commander`` tool is used to apply sign or MIC or encrypt binaries for Silicon Labs +devices. It can be invoked either by ``west sign`` when the ``sign.tool`` configuration is set to +``silabs_commander`` or by ``west build`` if ``CONFIG_SIWX91X_SIGN_KEY`` or +``CONFIG_SIWX91X_MIC_KEY`` is set. + +If one of ``CONFIG_SIWX91X_SIGN_KEY`` or ``CONFIG_SIWX91X_MIC_KEY`` is set, ``west flash`` will +automatically flash the signed version of the binary. + +``silabs_commander`` require `Simplicity Commander`_ to be install on the host. The provisionning of the +key on the device is described in `UG574 SiWx917 SoC Manufacturing Utility User Guide`_. + +.. _Simplicity Commander: + https://www.silabs.com/developer-tools/simplicity-studio/simplicity-commander?tab=downloads +.. _UG574 SiWx917 SoC Manufacturing Utility User Guide: + https://www.silabs.com/documents/public/user-guides/ug574-siwx917-soc-manufacturing-utility-user-guide.pdf From d533b1123f595854a5c3238cb54ffd9909d5562a Mon Sep 17 00:00:00 2001 From: Thomas Stranger Date: Mon, 28 Jul 2025 12:20:23 +0200 Subject: [PATCH 211/226] docs: update https links update a couple of links to use https instead of http Signed-off-by: Thomas Stranger --- doc/develop/west/build-flash-debug.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 2b7dd3ec..00cf2919 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -765,7 +765,7 @@ From that point on Renode can be used normally in both console and window modes. For details on using Renode see `Renode - documentation`_. .. _Renode - documentation: - http://docs.renode.io + https://docs.renode.io Runner-Specific Overrides ========================= From 46fea6dfa9bae624f6b1f8b753dce67b949bc64f Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Sun, 31 Aug 2025 14:04:18 +0000 Subject: [PATCH 212/226] doc: develop: west: alias: add example for auto-excluding platforms Add an example west alias for automatically excluding certain platforms when running Twister via west. This is especially useful for excluding the 32-bit native_sim target when running on hosts systems without a 32-bit host C library (i.e. Linux/AArch64). Signed-off-by: Henrik Brix Andersen --- doc/develop/west/alias.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/develop/west/alias.rst b/doc/develop/west/alias.rst index 5e55652e..f0093b5d 100644 --- a/doc/develop/west/alias.rst +++ b/doc/develop/west/alias.rst @@ -59,3 +59,11 @@ Override ``west update`` to check a local cache: .. code-block:: shell west config alias.update "update --path-cache $HOME/.cache/zephyrproject" + +Automatically exclude the 32-bit native simulator target when running :ref:`Twister +` via west. This is especially useful when running on hosts systems without a 32-bit +host C library (i.e. Linux/AArch64): + +.. code-block:: shell + + west config alias.twister "twister --exclude-platform native_sim/native" From a2f21edfa132a43a36e267ac6bf76a305a5cae66 Mon Sep 17 00:00:00 2001 From: Noah Pendleton Date: Fri, 29 Aug 2025 15:03:03 -0400 Subject: [PATCH 213/226] west: blobs: fetch `--allow-regex` filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building in CI for specific SOCs, it's useful to only have `west blobs fetch` pull a selected set of blob objects. This is especially helpful on `hal_espressif`, which currently has 78 blob objects. Add a `--allow-regex` arg to the `west blobs fetch` subcommand to filter only specified blobs, for example: ```bash # only download esp32 blobs, skip the other variants ❯ west blobs fetch hal_espressif --allow-regex 'lib/esp32/.*' ``` Also, replace all `str.format()` invocations with f-strings per review feedback. Signed-off-by: Noah Pendleton --- doc/develop/west/zephyr-cmds.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index ee5e8b28..f4b039fa 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -214,6 +214,12 @@ Additionally the tool allows you to specify the modules you want to list, fetch or clean blobs for by typing the module names as a command-line parameter. +The argument ``--allow-regex`` can be passed ``west blobs fetch`` to restrict +the specific blobs that are fetched, by passing a regular expression:: + + # For example, only download esp32 blobs, skip the other variants + west blobs fetch hal_espressif --allow-regex 'lib/esp32/.*' + .. _west-twister: Twister wrapper: ``west twister`` From ef487e0bed8329d79da40c11d15a95f4218dcf1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 18 Sep 2025 21:05:55 +0200 Subject: [PATCH 214/226] doc: west: remove old west 0.6 and 0.7 related troubleshooting entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit west 0.6.0 and 0.7.0 were released in 2019 and 2020 ; keeping troubleshooting information for these versions is not needed anymore (there isn't even a currently maintained LTS that would remotely be concerned by this). Signed-off-by: Benjamin Cabé --- doc/develop/west/troubleshooting.rst | 59 ---------------------------- 1 file changed, 59 deletions(-) diff --git a/doc/develop/west/troubleshooting.rst b/doc/develop/west/troubleshooting.rst index 8181d8cd..44f17d34 100644 --- a/doc/develop/west/troubleshooting.rst +++ b/doc/develop/west/troubleshooting.rst @@ -83,47 +83,6 @@ Then: #. Close your ``cmd.exe`` window and open a new one. You should be able to run ``west``. -"Error: unexpected keyword argument 'requires_workspace'" -********************************************************* - -This error occurs on some Linux distributions after upgrading to west 0.7.0 or -later from 0.6.x. For example: - -.. code-block:: none - - $ west update - [... stack trace ...] - TypeError: __init__() got an unexpected keyword argument 'requires_workspace' - -This appears to be a problem with the distribution's pip; see `this comment in -west issue 373`_ for details. Some versions of **Ubuntu** and **Linux Mint** are known to -have this problem. Some users report issues on Fedora as well. - -Neither macOS nor Windows users have reported this issue. There have been no -reports of this issue on other Linux distributions, like Arch Linux, either. - -.. _this comment in west issue 373: - https://github.com/zephyrproject-rtos/west/issues/373#issuecomment-583489272 - -**Workaround 1**: remove the old version, then upgrade: - -.. code-block:: none - - $ pip3 show west | grep Location: | cut -f 2 -d ' ' - /home/foo/.local/lib/python3.6/site-packages - $ rm -r /home/foo/.local/lib/python3.6/site-packages/west - $ pip3 install --user west==0.7.0 - -**Workaround 2**: install west in a Python virtual environment - -One option is to use the `venv module`_ that's part of the Python 3 standard -library. Some distributions remove this module from their base Python 3 -packages, so you may need to do some additional work to get it installed on -your system. - -.. _venv module: - https://docs.python.org/3/library/venv.html - "invalid choice: 'build'" (or 'flash', etc.) ******************************************** @@ -203,21 +162,3 @@ The easiest way to resolve this issue is to upgrade west and retry as follows: you will get the "already in a workspace" error message discussed next). #. Run ``west init`` again. - -"already in an installation" -**************************** - -You may see this error when running ``west init`` with west 0.6: - -.. code-block:: none - - FATAL ERROR: already in an installation (), aborting - -If this is unexpected and you're really trying to create a new west workspace, -then it's likely that west is using the :envvar:`ZEPHYR_BASE` :ref:`environment -variable ` to locate a workspace elsewhere on your system. - -This is intentional; it allows you to put your Zephyr applications in -any directory and still use west to build, flash, and debug them, for example. - -To resolve this issue, unset :envvar:`ZEPHYR_BASE` and try again. From 7bfbcf729731350c89294d83d9c1aba686b04677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 18 Sep 2025 22:28:06 +0200 Subject: [PATCH 215/226] doc: west: drop "Moving to West" doc page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converting a "pre-west" Zephyr setup is not something we officially support anymore so drop associated documentation. Signed-off-by: Benjamin Cabé --- doc/develop/west/index.rst | 1 - doc/develop/west/moving-to-west.rst | 57 ----------------------------- 2 files changed, 58 deletions(-) delete mode 100644 doc/develop/west/moving-to-west.rst diff --git a/doc/develop/west/index.rst b/doc/develop/west/index.rst index ce738179..0ad4cade 100644 --- a/doc/develop/west/index.rst +++ b/doc/develop/west/index.rst @@ -43,7 +43,6 @@ each command. sign.rst zephyr-cmds.rst why.rst - moving-to-west.rst without-west.rst For details on west's Python APIs, see :ref:`west-apis`. diff --git a/doc/develop/west/moving-to-west.rst b/doc/develop/west/moving-to-west.rst deleted file mode 100644 index d79ba199..00000000 --- a/doc/develop/west/moving-to-west.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. _moving-to-west: - -Moving to West -############## - -To convert a "pre-west" Zephyr setup on your computer to west, follow these -steps. If you are starting from scratch, use the :ref:`getting_started` -instead. See :ref:`west-troubleshooting` for advice on common issues. - -#. Install west. - - On Linux:: - - pip3 install --user -U west - - On Windows and macOS:: - - pip3 install -U west - - For details, see :ref:`west-install`. - -#. Move your zephyr repository to a new :file:`zephyrproject` parent directory, - and change directory there. - - On Linux and macOS:: - - mkdir zephyrproject - mv zephyr zephyrproject - cd zephyrproject - - On Windows ``cmd.exe``:: - - mkdir zephyrproject - move zephyr zephyrproject - chdir zephyrproject - - The name :file:`zephyrproject` is recommended, but you can choose any name - with no spaces anywhere in the path. - -#. Create a :ref:`west workspace ` using the zephyr - repository as a local manifest repository:: - - west init -l zephyr - - This creates :file:`zephyrproject/.west`, marking the root of your - workspace, and does some other setup. It will not change the contents of - the zephyr repository in any way. - -#. Clone the rest of the repositories used by zephyr:: - - west update - - **Make sure to run this command whenever you pull zephyr.** Otherwise, your - local repositories will get out of sync. (Run ``west list`` for current - information on these repositories.) - -You are done: :file:`zephyrproject` is now set up to use west. From 96eee9cec4107b1741b7bb4b9db124e718e066c6 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Sat, 20 Sep 2025 20:46:51 +0200 Subject: [PATCH 216/226] doc: develop: west: Add v1.5.0 release notes Add a section to the west release notes for v1.5.0. Signed-off-by: Pieter De Gendt --- doc/develop/west/release-notes.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 861406cd..159fd63b 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -3,6 +3,26 @@ West Release Notes ################## +v1.5.0 +****** + +Major changes: + +- Add support for auto-caching. + Pass the ``--auto-cache `` argument to ``west update``. + +Other changes: + +- Allow combining ``--name-cache`` and ``--path-cache`` for ``west update``. + +- Document default revision value in the manifest schema. + +Bug fixes: + +- Allow empty or missing manifest projects list. + +- Make ``manifest.group-filter`` list order deterministic when freezing or resolving manifest files. + v1.4.0 ****** From be213598ce0d510f499d8c6b948e834e8db960fb Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Tue, 23 Sep 2025 21:20:41 +0200 Subject: [PATCH 217/226] doc: develop: west: config: Add auto-cache Add an entry to the west configuration table for auto-cache. Signed-off-by: Pieter De Gendt --- doc/develop/west/config.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/develop/west/config.rst b/doc/develop/west/config.rst index 51420abb..563b9c9c 100644 --- a/doc/develop/west/config.rst +++ b/doc/develop/west/config.rst @@ -227,6 +227,9 @@ commands are documented in the pages for those commands. +foo,,-bar +foo,-bar + * - ``update.auto-cache`` + - String. If non-empty, ``west update`` will use its value as the + ``--auto-cache`` option's value if not given on the command line. * - ``update.fetch`` - String, one of ``"smart"`` (the default behavior starting in v0.6.1) or ``"always"`` (the previous behavior). If set to ``"smart"``, the From 5e93683bf12c225f03576a698bd05b29efb7a98d Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 16 Sep 2025 17:40:54 -0500 Subject: [PATCH 218/226] scripts: flash: Add west config for flash skip rebuild Add a west config option to skip rebuilds by default or not when doing west flash. Also add corresponding symmetrical CLI options. Signed-off-by: Declan Snyder --- doc/develop/west/build-flash-debug.rst | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 00cf2919..a183108d 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -551,6 +551,22 @@ only the image from this domain:: .. _west-debugging: +Configuration Options +===================== + +You can :ref:`configure ` ``west flash`` using these options. + +.. NOTE: docs authors: keep this table sorted alphabetically + +.. list-table:: + :widths: 10 30 + :header-rows: 1 + + * - Option + - Description + * - ``flash.rebuild`` + - Boolean, default ``true``. If ``false``, do not rebuild on west flash. + Debugging: ``west debug``, ``west debugserver`` *********************************************** @@ -683,6 +699,25 @@ to debug:: .. _west-runner: +Configuration Options +===================== + +You can :ref:`configure ` ``west debug`` and +:ref:`configure ` ``west debugserver`` using these options. + +.. NOTE: docs authors: keep this table sorted alphabetically + +.. list-table:: + :widths: 10 30 + :header-rows: 1 + + * - Option + - Description + * - ``debug.rebuild`` + - Boolean, default ``true``. If ``false``, do not rebuild on west debug. + * - ``debugserver.rebuild`` + - Boolean, default ``true``. If ``false``, do not rebuild on west debugserver. + Flash and debug runners *********************** From 405d94eccbb13cd635e1dfb8900ea893f965f686 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Mon, 20 Oct 2025 17:29:33 +0200 Subject: [PATCH 219/226] west: bindesc: add extract subcommand Add a new 'west bindesc extract' subcommand that dumps all binary descriptors into a separate binary file. It will also report the range (offset and length) of the dumped data within the original image. Signed-off-by: Luca Burelli --- doc/develop/west/zephyr-cmds.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index f4b039fa..47e17390 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -252,6 +252,10 @@ You can dump all of the descriptors in an image using:: west bindesc dump build/zephyr/zephyr.bin +You can extract the descriptor data area of the image to a file using:: + + west bindesc extract + You can list all known standard descriptor names using:: west bindesc list From 7a0d0a3371709dd561d2d1eb94b460e465131205 Mon Sep 17 00:00:00 2001 From: Thorsten Klein Date: Fri, 24 Oct 2025 15:28:06 +0200 Subject: [PATCH 220/226] doc: develop: west: config option build.dir-fmt new format arguments for config option build.dir-fmt are documented accordingly. Signed-off-by: Thorsten Klein --- doc/develop/west/build-flash-debug.rst | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index a183108d..50bb8210 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -395,10 +395,23 @@ You can :ref:`configure ` ``west build`` using these options. west whenever it needs to create or locate a build folder. The currently available arguments are: + - ``west_topdir``: The absolute path to the west workspace, as + returned by the ``west_topdir`` command - ``board``: The board name - - ``source_dir``: The relative path from the current working directory - to the source directory. If the current working directory is inside - the source directory this will be set to an empty string. + - ``source_dir``: Path to the CMake source directory, relative to the + current working directory. If the current working directory is + inside the source directory, this is an empty string. If no source + directory is specified, it defaults to current working directory. + E.g. if ``west build ../app`` is run from ``/app1``, + ``source_dir`` resolves to ``../app`` (which is the relative path + to the current working dir). + - ``source_dir_workspace``: Path to the source directory, relative to + ``west_topdir`` (if it is inside the workspace). Otherwise, it is + relative to the filesystem root (``/`` on Unix, respectively + ``C:/`` on Windows). + E.g. if ``west build ../app`` is run from ``/app1``, + ``source_dir`` resolves to ``app`` (which is the relative path to + the west workspace dir). - ``app``: The name of the source directory. * - ``build.generator`` - String, default ``Ninja``. The `CMake Generator`_ to use to create a From 0874a58fe8c38b40368d6b13ef704a20cc4d2e29 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 1 Oct 2025 08:31:46 +0200 Subject: [PATCH 221/226] pyproject.toml: Add docs group with sphinx Add the sphinx package to a separate dependency group. Signed-off-by: Pieter De Gendt --- pyproject.toml | 5 + uv.lock | 433 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 437 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 54d1599e..6c581330 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,11 @@ dev = [ {include-group = "test"}, {include-group = "types"}, ] +docs = [ + "sphinx~=8.1", + "sphinx-rtd-theme~=3.0", + "sphinx-tabs~=3.4", +] [tool.setuptools] package-dir = {"" = "src"} diff --git a/uv.lock b/uv.lock index 430159d7..ef429cad 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,101 @@ version = 1 revision = 3 requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.11'", + "python_full_version < '3.11'", +] + +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/98/f3b8013223728a99b908c9344da3aa04ee6e3fa235f19409033eda92fb78/charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72", size = 207695, upload-time = "2025-08-09T07:55:36.452Z" }, + { url = "https://files.pythonhosted.org/packages/21/40/5188be1e3118c82dcb7c2a5ba101b783822cfb413a0268ed3be0468532de/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe", size = 147153, upload-time = "2025-08-09T07:55:38.467Z" }, + { url = "https://files.pythonhosted.org/packages/37/60/5d0d74bc1e1380f0b72c327948d9c2aca14b46a9efd87604e724260f384c/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601", size = 160428, upload-time = "2025-08-09T07:55:40.072Z" }, + { url = "https://files.pythonhosted.org/packages/85/9a/d891f63722d9158688de58d050c59dc3da560ea7f04f4c53e769de5140f5/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c", size = 157627, upload-time = "2025-08-09T07:55:41.706Z" }, + { url = "https://files.pythonhosted.org/packages/65/1a/7425c952944a6521a9cfa7e675343f83fd82085b8af2b1373a2409c683dc/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2", size = 152388, upload-time = "2025-08-09T07:55:43.262Z" }, + { url = "https://files.pythonhosted.org/packages/f0/c9/a2c9c2a355a8594ce2446085e2ec97fd44d323c684ff32042e2a6b718e1d/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0", size = 150077, upload-time = "2025-08-09T07:55:44.903Z" }, + { url = "https://files.pythonhosted.org/packages/3b/38/20a1f44e4851aa1c9105d6e7110c9d020e093dfa5836d712a5f074a12bf7/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0", size = 161631, upload-time = "2025-08-09T07:55:46.346Z" }, + { url = "https://files.pythonhosted.org/packages/a4/fa/384d2c0f57edad03d7bec3ebefb462090d8905b4ff5a2d2525f3bb711fac/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0", size = 159210, upload-time = "2025-08-09T07:55:47.539Z" }, + { url = "https://files.pythonhosted.org/packages/33/9e/eca49d35867ca2db336b6ca27617deed4653b97ebf45dfc21311ce473c37/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a", size = 153739, upload-time = "2025-08-09T07:55:48.744Z" }, + { url = "https://files.pythonhosted.org/packages/2a/91/26c3036e62dfe8de8061182d33be5025e2424002125c9500faff74a6735e/charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f", size = 99825, upload-time = "2025-08-09T07:55:50.305Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/f05db471f81af1fa01839d44ae2a8bfeec8d2a8b4590f16c4e7393afd323/charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669", size = 107452, upload-time = "2025-08-09T07:55:51.461Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b5/991245018615474a60965a7c9cd2b4efbaabd16d582a5547c47ee1c7730b/charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b", size = 204483, upload-time = "2025-08-09T07:55:53.12Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/ae245c41c06299ec18262825c1569c5d3298fc920e4ddf56ab011b417efd/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64", size = 145520, upload-time = "2025-08-09T07:55:54.712Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a4/b3b6c76e7a635748c4421d2b92c7b8f90a432f98bda5082049af37ffc8e3/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91", size = 158876, upload-time = "2025-08-09T07:55:56.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e6/63bb0e10f90a8243c5def74b5b105b3bbbfb3e7bb753915fe333fb0c11ea/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f", size = 156083, upload-time = "2025-08-09T07:55:57.582Z" }, + { url = "https://files.pythonhosted.org/packages/87/df/b7737ff046c974b183ea9aa111b74185ac8c3a326c6262d413bd5a1b8c69/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07", size = 150295, upload-time = "2025-08-09T07:55:59.147Z" }, + { url = "https://files.pythonhosted.org/packages/61/f1/190d9977e0084d3f1dc169acd060d479bbbc71b90bf3e7bf7b9927dec3eb/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30", size = 148379, upload-time = "2025-08-09T07:56:00.364Z" }, + { url = "https://files.pythonhosted.org/packages/4c/92/27dbe365d34c68cfe0ca76f1edd70e8705d82b378cb54ebbaeabc2e3029d/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14", size = 160018, upload-time = "2025-08-09T07:56:01.678Z" }, + { url = "https://files.pythonhosted.org/packages/99/04/baae2a1ea1893a01635d475b9261c889a18fd48393634b6270827869fa34/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c", size = 157430, upload-time = "2025-08-09T07:56:02.87Z" }, + { url = "https://files.pythonhosted.org/packages/2f/36/77da9c6a328c54d17b960c89eccacfab8271fdaaa228305330915b88afa9/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae", size = 151600, upload-time = "2025-08-09T07:56:04.089Z" }, + { url = "https://files.pythonhosted.org/packages/64/d4/9eb4ff2c167edbbf08cdd28e19078bf195762e9bd63371689cab5ecd3d0d/charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849", size = 99616, upload-time = "2025-08-09T07:56:05.658Z" }, + { url = "https://files.pythonhosted.org/packages/f4/9c/996a4a028222e7761a96634d1820de8a744ff4327a00ada9c8942033089b/charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c", size = 107108, upload-time = "2025-08-09T07:56:07.176Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] [[package]] name = "colorama" @@ -121,18 +216,45 @@ version = "0.6.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, +] + [[package]] name = "exceptiongroup" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, ] +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, +] + [[package]] name = "iniconfig" version = "2.1.0" @@ -142,6 +264,103 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + [[package]] name = "mypy" version = "1.18.2" @@ -377,6 +596,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "roman-numerals-py" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017, upload-time = "2025-02-22T07:34:54.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742, upload-time = "2025-02-22T07:34:52.422Z" }, +] + [[package]] name = "ruamel-yaml" version = "0.18.15" @@ -476,6 +719,174 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "sphinx" +version = "8.1.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "alabaster", marker = "python_full_version < '3.11'" }, + { name = "babel", marker = "python_full_version < '3.11'" }, + { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, + { name = "docutils", marker = "python_full_version < '3.11'" }, + { name = "imagesize", marker = "python_full_version < '3.11'" }, + { name = "jinja2", marker = "python_full_version < '3.11'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pygments", marker = "python_full_version < '3.11'" }, + { name = "requests", marker = "python_full_version < '3.11'" }, + { name = "snowballstemmer", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.11'" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125, upload-time = "2024-10-13T20:27:10.448Z" }, +] + +[[package]] +name = "sphinx" +version = "8.2.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +dependencies = [ + { name = "alabaster", marker = "python_full_version >= '3.11'" }, + { name = "babel", marker = "python_full_version >= '3.11'" }, + { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, + { name = "docutils", marker = "python_full_version >= '3.11'" }, + { name = "imagesize", marker = "python_full_version >= '3.11'" }, + { name = "jinja2", marker = "python_full_version >= '3.11'" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pygments", marker = "python_full_version >= '3.11'" }, + { name = "requests", marker = "python_full_version >= '3.11'" }, + { name = "roman-numerals-py", marker = "python_full_version >= '3.11'" }, + { name = "snowballstemmer", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, +] + +[[package]] +name = "sphinx-rtd-theme" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-jquery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463, upload-time = "2024-11-13T11:06:04.545Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13", size = 7655561, upload-time = "2024-11-13T11:06:02.094Z" }, +] + +[[package]] +name = "sphinx-tabs" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "pygments" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/53/a9a91995cb365e589f413b77fc75f1c0e9b4ac61bfa8da52a779ad855cc0/sphinx-tabs-3.4.7.tar.gz", hash = "sha256:991ad4a424ff54119799ba1491701aa8130dd43509474aef45a81c42d889784d", size = 15891, upload-time = "2024-10-08T13:37:27.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/c6/f47505b564b918a3ba60c1e99232d4942c4a7e44ecaae603e829e3d05dae/sphinx_tabs-3.4.7-py3-none-any.whl", hash = "sha256:c12d7a36fd413b369e9e9967a0a4015781b71a9c393575419834f19204bd1915", size = 9727, upload-time = "2024-10-08T13:37:26.192Z" }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, +] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, +] + [[package]] name = "tomli" version = "2.3.0" @@ -543,6 +954,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + [[package]] name = "west" version = "1.5.99" @@ -564,6 +984,12 @@ dev = [ { name = "ruff" }, { name = "types-pyyaml" }, ] +docs = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx-rtd-theme" }, + { name = "sphinx-tabs" }, +] lint = [ { name = "ruff" }, ] @@ -595,6 +1021,11 @@ dev = [ { name = "ruff", specifier = "~=0.13" }, { name = "types-pyyaml", specifier = "~=6.0" }, ] +docs = [ + { name = "sphinx", specifier = "~=8.1" }, + { name = "sphinx-rtd-theme", specifier = "~=3.0" }, + { name = "sphinx-tabs", specifier = "~=3.4" }, +] lint = [{ name = "ruff", specifier = "~=0.13" }] test = [ { name = "coverage", specifier = "~=7.10" }, From 1f48927ef289f20a8094f8525d5d7b4944ae4609 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 6 Nov 2025 19:58:11 +0100 Subject: [PATCH 222/226] doc: Move west to top-level doc/ directory Transfer the west documentation from the Zephyr doc/develop/west directory to the West doc/ location. Signed-off-by: Pieter De Gendt --- doc/{develop/west => }/alias.rst | 0 doc/{develop/west => }/basics.rst | 0 doc/{develop/west => }/build-flash-debug.rst | 0 doc/{develop/west => }/built-in.rst | 0 doc/{develop/west => }/config.rst | 0 doc/{develop/west => }/extensions.rst | 0 doc/{develop/west => }/index.rst | 0 doc/{develop/west => }/install.rst | 0 doc/{develop/west => }/manifest.rst | 0 doc/{develop/west => }/release-notes.rst | 0 doc/{develop/west => }/sign.rst | 0 doc/{develop/west => }/troubleshooting.rst | 0 doc/{develop/west => }/west-apis.rst | 0 doc/{develop/west => }/west-mr-model.png | Bin doc/{develop/west => }/west-not-found.rst | 0 doc/{develop/west => }/why.rst | 0 doc/{develop/west => }/without-west.rst | 0 doc/{develop/west => }/workspaces.rst | 0 doc/{develop/west => }/zephyr-cmds.rst | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename doc/{develop/west => }/alias.rst (100%) rename doc/{develop/west => }/basics.rst (100%) rename doc/{develop/west => }/build-flash-debug.rst (100%) rename doc/{develop/west => }/built-in.rst (100%) rename doc/{develop/west => }/config.rst (100%) rename doc/{develop/west => }/extensions.rst (100%) rename doc/{develop/west => }/index.rst (100%) rename doc/{develop/west => }/install.rst (100%) rename doc/{develop/west => }/manifest.rst (100%) rename doc/{develop/west => }/release-notes.rst (100%) rename doc/{develop/west => }/sign.rst (100%) rename doc/{develop/west => }/troubleshooting.rst (100%) rename doc/{develop/west => }/west-apis.rst (100%) rename doc/{develop/west => }/west-mr-model.png (100%) rename doc/{develop/west => }/west-not-found.rst (100%) rename doc/{develop/west => }/why.rst (100%) rename doc/{develop/west => }/without-west.rst (100%) rename doc/{develop/west => }/workspaces.rst (100%) rename doc/{develop/west => }/zephyr-cmds.rst (100%) diff --git a/doc/develop/west/alias.rst b/doc/alias.rst similarity index 100% rename from doc/develop/west/alias.rst rename to doc/alias.rst diff --git a/doc/develop/west/basics.rst b/doc/basics.rst similarity index 100% rename from doc/develop/west/basics.rst rename to doc/basics.rst diff --git a/doc/develop/west/build-flash-debug.rst b/doc/build-flash-debug.rst similarity index 100% rename from doc/develop/west/build-flash-debug.rst rename to doc/build-flash-debug.rst diff --git a/doc/develop/west/built-in.rst b/doc/built-in.rst similarity index 100% rename from doc/develop/west/built-in.rst rename to doc/built-in.rst diff --git a/doc/develop/west/config.rst b/doc/config.rst similarity index 100% rename from doc/develop/west/config.rst rename to doc/config.rst diff --git a/doc/develop/west/extensions.rst b/doc/extensions.rst similarity index 100% rename from doc/develop/west/extensions.rst rename to doc/extensions.rst diff --git a/doc/develop/west/index.rst b/doc/index.rst similarity index 100% rename from doc/develop/west/index.rst rename to doc/index.rst diff --git a/doc/develop/west/install.rst b/doc/install.rst similarity index 100% rename from doc/develop/west/install.rst rename to doc/install.rst diff --git a/doc/develop/west/manifest.rst b/doc/manifest.rst similarity index 100% rename from doc/develop/west/manifest.rst rename to doc/manifest.rst diff --git a/doc/develop/west/release-notes.rst b/doc/release-notes.rst similarity index 100% rename from doc/develop/west/release-notes.rst rename to doc/release-notes.rst diff --git a/doc/develop/west/sign.rst b/doc/sign.rst similarity index 100% rename from doc/develop/west/sign.rst rename to doc/sign.rst diff --git a/doc/develop/west/troubleshooting.rst b/doc/troubleshooting.rst similarity index 100% rename from doc/develop/west/troubleshooting.rst rename to doc/troubleshooting.rst diff --git a/doc/develop/west/west-apis.rst b/doc/west-apis.rst similarity index 100% rename from doc/develop/west/west-apis.rst rename to doc/west-apis.rst diff --git a/doc/develop/west/west-mr-model.png b/doc/west-mr-model.png similarity index 100% rename from doc/develop/west/west-mr-model.png rename to doc/west-mr-model.png diff --git a/doc/develop/west/west-not-found.rst b/doc/west-not-found.rst similarity index 100% rename from doc/develop/west/west-not-found.rst rename to doc/west-not-found.rst diff --git a/doc/develop/west/why.rst b/doc/why.rst similarity index 100% rename from doc/develop/west/why.rst rename to doc/why.rst diff --git a/doc/develop/west/without-west.rst b/doc/without-west.rst similarity index 100% rename from doc/develop/west/without-west.rst rename to doc/without-west.rst diff --git a/doc/develop/west/workspaces.rst b/doc/workspaces.rst similarity index 100% rename from doc/develop/west/workspaces.rst rename to doc/workspaces.rst diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/zephyr-cmds.rst similarity index 100% rename from doc/develop/west/zephyr-cmds.rst rename to doc/zephyr-cmds.rst From de3dd53ffd5a30753f4d3118ce3d73db8c0e035d Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 6 Nov 2025 20:06:01 +0100 Subject: [PATCH 223/226] doc: Remove Zephyr specific files Remove files that document west extensions from the Zephyr repository. Signed-off-by: Pieter De Gendt --- doc/build-flash-debug.rst | 892 -------------------------------------- doc/index.rst | 4 - doc/sign.rst | 80 ---- doc/west-not-found.rst | 16 - doc/without-west.rst | 128 ------ doc/zephyr-cmds.rst | 434 ------------------- 6 files changed, 1554 deletions(-) delete mode 100644 doc/build-flash-debug.rst delete mode 100644 doc/sign.rst delete mode 100644 doc/west-not-found.rst delete mode 100644 doc/without-west.rst delete mode 100644 doc/zephyr-cmds.rst diff --git a/doc/build-flash-debug.rst b/doc/build-flash-debug.rst deleted file mode 100644 index 50bb8210..00000000 --- a/doc/build-flash-debug.rst +++ /dev/null @@ -1,892 +0,0 @@ -.. _west-build-flash-debug: - -Building, Flashing and Debugging -################################ - -Zephyr provides several :ref:`west extension commands ` for -building, flashing, and interacting with Zephyr programs running on a board: -``build``, ``flash``, ``debug``, ``debugserver`` and ``attach``. - -For information on adding board support for the flashing and debugging -commands, see :ref:`flash-and-debug-support` in the board porting guide. - -.. Add a per-page contents at the top of the page. This page is nested - deeply enough that it doesn't have any subheadings in the main nav. - -.. only:: html - - .. contents:: - :local: - -.. _west-building: - -Building: ``west build`` -************************ - -.. tip:: Run ``west build -h`` for a quick overview. - -The ``build`` command helps you build Zephyr applications from source. You can -use :ref:`west config ` to configure its behavior. - -Its default behavior tries to "do what you mean": - -- If there is a Zephyr build directory named :file:`build` in your current - working directory, it is incrementally re-compiled. The same is true if you - run ``west build`` from a Zephyr build directory. - -- Otherwise, if you run ``west build`` from a Zephyr application's source - directory and no build directory is found, a new one is created and the - application is compiled in it. - -Basics -====== - -The easiest way to use ``west build`` is to go to an application's root -directory (i.e. the folder containing the application's :file:`CMakeLists.txt`) -and then run:: - - west build -b - -Where ```` is the name of the board you want to build for. This is -exactly the same name you would supply to CMake if you were to invoke it with: -``cmake -DBOARD=``. - -.. tip:: - - You can use the :ref:`west boards ` command to list all - supported boards. - -A build directory named :file:`build` will be created, and the application will -be compiled there after ``west build`` runs CMake to create a build system in -that directory. If ``west build`` finds an existing build directory, the -application is incrementally re-compiled there without re-running CMake. You -can force CMake to run again with ``--cmake``. - -You don't need to use the ``--board`` option if you've already got an existing -build directory; ``west build`` can figure out the board from the CMake cache. -For new builds, the ``--board`` option, :envvar:`BOARD` environment variable, -or ``build.board`` configuration option are checked (in that order). - -.. _west-multi-domain-builds: - -Sysbuild (multi-domain builds) -============================== - -:ref:`sysbuild` can be used to create a multi-domain build system combining -multiple images for a single or multiple boards. - -Use ``--sysbuild`` to select the :ref:`sysbuild` build infrastructure with -``west build`` to build multiple domains. - -More detailed information regarding the use of sysbuild can be found in the -:ref:`sysbuild` guide. - -.. tip:: - - The ``build.sysbuild`` configuration option can be enabled to tell - ``west build`` to default build using sysbuild. - ``--no-sysbuild`` can be used to disable sysbuild for a specific build. - -``west build`` will build all domains through the top-level build folder of the -domains specified by sysbuild. - -A single domain from a multi-domain project can be built by using ``--domain`` -argument. - -Examples -======== - -Here are some ``west build`` usage examples, grouped by area. - -Forcing CMake to Run Again --------------------------- - -To force a CMake re-run, use the ``--cmake`` (or ``-c``) option:: - - west build -c - -Setting a Default Board ------------------------ - -To configure ``west build`` to build for the ``reel_board`` by default:: - - west config build.board reel_board - -(You can use any other board supported by Zephyr here; it doesn't have to be -``reel_board``.) - -.. _west-building-dirs: - -Setting Source and Build Directories ------------------------------------- - -To set the application source directory explicitly, give its path as a -positional argument:: - - west build -b path/to/source/directory - -To set the build directory explicitly, use ``--build-dir`` (or ``-d``):: - - west build -b --build-dir path/to/build/directory - -To change the default build directory from :file:`build`, use the -``build.dir-fmt`` configuration option. This lets you name build -directories using format strings, like this:: - - west config build.dir-fmt "build/{board}/{app}" - -With the above, running ``west build -b reel_board samples/hello_world`` will -use build directory :file:`build/reel_board/hello_world`. See -:ref:`west-building-config` for more details on this option. - -Setting the Build System Target -------------------------------- - -To specify the build system target to run, use ``--target`` (or ``-t``). - -For example, on host platforms with QEMU, you can use the ``run`` target to -build and run the :zephyr:code-sample:`hello_world` sample for the emulated -:zephyr:board:`qemu_x86 ` board in one command:: - - west build -b qemu_x86 -t run samples/hello_world - -As another example, to use ``-t`` to list all build system targets:: - - west build -t help - -As a final example, to use ``-t`` to run the ``pristine`` target, which deletes -all the files in the build directory:: - - west build -t pristine - -.. _west-building-pristine: - -Pristine Builds ---------------- - -A *pristine* build directory is essentially a new build directory. All -byproducts from previous builds have been removed. - -To force ``west build`` make the build directory pristine before re-running -CMake to generate a build system, use the ``--pristine=always`` (or -``-p=always``) option. - -Giving ``--pristine`` or ``-p`` without a value has the same effect as giving -it the value ``always``. For example, these commands are equivalent:: - - west build -p -b reel_board samples/hello_world - west build -p=always -b reel_board samples/hello_world - -By default, ``west build`` makes no attempt to detect if the build directory -needs to be made pristine. This can lead to errors if you do something like -try to reuse a build directory for a different ``--board``. - -Using ``--pristine=auto`` makes ``west build`` detect some of these situations -and make the build directory pristine before trying the build. - -.. tip:: - - You can run ``west config build.pristine always`` to always do a pristine - build, or ``west config build.pristine never`` to disable the heuristic. - See the ``west build`` :ref:`west-building-config` for details. - -.. _west-building-verbose: - -Verbose Builds --------------- - -To print the CMake and compiler commands run by ``west build``, use the global -west verbosity option, ``-v``:: - - west -v build -b reel_board samples/hello_world - -.. _west-building-generator: -.. _west-building-cmake-args: - -One-Time CMake Arguments ------------------------- - -To pass additional arguments to the CMake invocation performed by ``west -build``, pass them after a ``--`` at the end of the command line. - -.. important:: - - Passing additional CMake arguments like this forces ``west build`` to re-run - the CMake build configuration step, even if a build system has already been - generated. This will make incremental builds slower (but still much faster - than building from scratch). - - After using ``--`` once to generate the build directory, use ``west build -d - `` on subsequent runs to do incremental builds. - - Alternatively, make your CMake arguments permanent as described in the next - section; it will not slow down incremental builds. - -For example, to use the Unix Makefiles CMake generator instead of Ninja (which -``west build`` uses by default), run:: - - west build -b reel_board -- -G'Unix Makefiles' - -To use Unix Makefiles and set `CMAKE_VERBOSE_MAKEFILE`_ to ``ON``:: - - west build -b reel_board -- -G'Unix Makefiles' -DCMAKE_VERBOSE_MAKEFILE=ON - -Notice how the ``--`` only appears once, even though multiple CMake arguments -are given. All command-line arguments to ``west build`` after a ``--`` are -passed to CMake. - -.. _west-building-dtc-overlay-file: - -To set :ref:`DTC_OVERLAY_FILE ` to -:file:`enable-modem.overlay`, using that file as a -:ref:`devicetree overlay `:: - - west build -b reel_board -- -DDTC_OVERLAY_FILE=enable-modem.overlay - -To merge the :file:`file.conf` Kconfig fragment into your build's -:file:`.config`:: - - west build -- -DEXTRA_CONF_FILE=file.conf - -.. _west-building-cmake-config: - -Permanent CMake Arguments -------------------------- - -The previous section describes how to add CMake arguments for a single ``west -build`` command. If you want to save CMake arguments for ``west build`` to use -every time it generates a new build system instead, you should use the -``build.cmake-args`` configuration option. Whenever ``west build`` runs CMake -to generate a build system, it splits this option's value according to shell -rules and includes the results in the ``cmake`` command line. - -Remember that, by default, ``west build`` **tries to avoid generating a new -build system if one is present** in your build directory. Therefore, you need -to either delete any existing build directories or do a :ref:`pristine build -` after setting ``build.cmake-args`` to make sure it -will take effect. - -For example, to always enable :makevar:`CMAKE_EXPORT_COMPILE_COMMANDS`, you can -run:: - - west config build.cmake-args -- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - -(The extra ``--`` is used to force the rest of the command to be treated as a -positional argument. Without it, :ref:`west config ` would -treat the ``-DVAR=VAL`` syntax as a use of its ``-D`` option.) - -To enable :makevar:`CMAKE_VERBOSE_MAKEFILE`, so CMake always produces a verbose -build system:: - - west config build.cmake-args -- -DCMAKE_VERBOSE_MAKEFILE=ON - -To save more than one argument in ``build.cmake-args``, use a single string -whose value can be split into distinct arguments (``west build`` uses the -Python function `shlex.split()`_ internally to split the value). - -.. _shlex.split(): https://docs.python.org/3/library/shlex.html#shlex.split - -For example, to enable both :makevar:`CMAKE_EXPORT_COMPILE_COMMANDS` and -:makevar:`CMAKE_VERBOSE_MAKEFILE`:: - - west config build.cmake-args -- "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_VERBOSE_MAKEFILE=ON" - -If you want to save your CMake arguments in a separate file instead, you can -combine CMake's ``-C `` option with ``build.cmake-args``. For -instance, another way to set the options used in the previous example is to -create a file named :file:`~/my-cache.cmake` with the following contents: - -.. code-block:: cmake - - set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "") - set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "") - -Then run:: - - west config build.cmake-args "-C ~/my-cache.cmake" - -See the `cmake(1) manual page`_ and the `set() command`_ documentation for -more details. - -.. _cmake(1) manual page: - https://cmake.org/cmake/help/latest/manual/cmake.1.html - -.. _set() command: - https://cmake.org/cmake/help/latest/command/set.html - -Build tool arguments --------------------- - -Use ``-o`` to pass options to the underlying build tool. - -This works with both ``ninja`` (:ref:`the default `) -and ``make`` based build systems. - -For example, to pass ``-dexplain`` to ``ninja``:: - - west build -o=-dexplain - -As another example, to pass ``--keep-going`` to ``make``:: - - west build -o=--keep-going - -Note that using ``-o=--foo`` instead of ``-o --foo`` is required to prevent -``--foo`` from being treated as a ``west build`` option. - -Build parallelism ------------------ - -By default, ``ninja`` uses all of your cores to build, while ``make`` uses only -one. You can control this explicitly with the ``-j`` option supported by both -tools. - -For example, to build with 4 cores:: - - west build -o=-j4 - -The ``-o`` option is described further in the previous section. - -Build a single domain ---------------------- - -In a multi-domain build with :zephyr:code-sample:`hello_world` and `MCUboot`_, you can use -``--domain hello_world`` to only build this domain:: - - west build --sysbuild --domain hello_world - -The ``--domain`` argument can be combined with the ``--target`` argument to -build the specific target for the target, for example:: - - west build --sysbuild --domain hello_world --target help - -Use a snippet -------------- - -See :ref:`using-snippets`. - -.. _west-building-config: - -Configuration Options -===================== - -You can :ref:`configure ` ``west build`` using these options. - -.. NOTE: docs authors: keep this table sorted alphabetically - -.. list-table:: - :widths: 10 30 - :header-rows: 1 - - * - Option - - Description - * - ``build.board`` - - String. If given, this the board used by :ref:`west build - ` when ``--board`` is not given and ``BOARD`` - is unset in the environment. - * - ``build.board_warn`` - - Boolean, default ``true``. If ``false``, disables warnings when - ``west build`` can't figure out the target board. - * - ``build.cmake-args`` - - String. If present, the value will be split according to shell rules and - passed to CMake whenever a new build system is generated. See - :ref:`west-building-cmake-config`. - * - ``build.dir-fmt`` - - String, default ``build``. The build folder format string, used by - west whenever it needs to create or locate a build folder. The currently - available arguments are: - - - ``west_topdir``: The absolute path to the west workspace, as - returned by the ``west_topdir`` command - - ``board``: The board name - - ``source_dir``: Path to the CMake source directory, relative to the - current working directory. If the current working directory is - inside the source directory, this is an empty string. If no source - directory is specified, it defaults to current working directory. - E.g. if ``west build ../app`` is run from ``/app1``, - ``source_dir`` resolves to ``../app`` (which is the relative path - to the current working dir). - - ``source_dir_workspace``: Path to the source directory, relative to - ``west_topdir`` (if it is inside the workspace). Otherwise, it is - relative to the filesystem root (``/`` on Unix, respectively - ``C:/`` on Windows). - E.g. if ``west build ../app`` is run from ``/app1``, - ``source_dir`` resolves to ``app`` (which is the relative path to - the west workspace dir). - - ``app``: The name of the source directory. - * - ``build.generator`` - - String, default ``Ninja``. The `CMake Generator`_ to use to create a - build system. (To set a generator for a single build, see the - :ref:`above example `) - * - ``build.guess-dir`` - - String, instructs west whether to try to guess what build folder to use - when ``build.dir-fmt`` is in use and not enough information is available - to resolve the build folder name. Can take these values: - - - ``never`` (default): Never try to guess, bail out instead and - require the user to provide a build folder with ``-d``. - - ``runners``: Try to guess the folder when using any of the 'runner' - commands. These are typically all commands that invoke an external - tool, such as ``flash`` and ``debug``. - * - ``build.pristine`` - - String. Controls the way in which ``west build`` may clean the build - folder before building. Can take the following values: - - - ``never`` (default): Never automatically make the build folder - pristine. - - ``auto``: ``west build`` will automatically make the build folder - pristine before building, if a build system is present and the build - would fail otherwise (e.g. the user has specified a different board - or application from the one previously used to make the build - directory). - - ``always``: Always make the build folder pristine before building, if - a build system is present. - * - ``build.sysbuild`` - - Boolean, default ``false``. If ``true``, build application using the - sysbuild infrastructure. - -.. _west-flashing: - -Flashing: ``west flash`` -************************ - -.. tip:: Run ``west flash -h`` for additional help. - -Basics -====== - -From a Zephyr build directory, re-build the binary and flash it to -your board:: - - west flash - -Without options, the behavior is the same as ``ninja flash`` (or -``make flash``, etc.). - -To specify the build directory, use ``--build-dir`` (or ``-d``):: - - west flash --build-dir path/to/build/directory - -If you don't specify the build directory, ``west flash`` searches for one in -:file:`build`, then the current working directory. If you set the -``build.dir-fmt`` configuration option (see :ref:`west-building-dirs`), ``west -flash`` searches there instead of :file:`build`. - -Choosing a Runner -================= - -If your board's Zephyr integration supports flashing with multiple -programs, you can specify which one to use using the ``--runner`` (or -``-r``) option. For example, if West flashes your board with -``nrfjprog`` by default, but it also supports JLink, you can override -the default with:: - - west flash --runner jlink - -You can override the default flash runner at build time by using the -``BOARD_FLASH_RUNNER`` CMake variable, and the debug runner with -``BOARD_DEBUG_RUNNER``. - -For example:: - - # Set the default runner to "jlink", overriding the board's - # usual default. - west build [...] -- -DBOARD_FLASH_RUNNER=jlink - -See :ref:`west-building-cmake-args` and :ref:`west-building-cmake-config` for -more information on setting CMake arguments. - -See :ref:`west-runner` below for more information on the ``runner`` -library used by West. The list of runners which support flashing can -be obtained with ``west flash -H``; if run from a build directory or -with ``--build-dir``, this will print additional information on -available runners for your board. - -Configuration Overrides -======================= - -The CMake cache contains default values West uses while flashing, such -as where the board directory is on the file system, the path to the -zephyr binaries to flash in several formats, and more. You can -override any of this configuration at runtime with additional options. - -For example, to override the HEX file containing the Zephyr image to -flash (assuming your runner expects a HEX file), but keep other -flash configuration at default values:: - - west flash --hex-file path/to/some/other.hex - -The ``west flash -h`` output includes a complete list of overrides -supported by all runners. - -Runner-Specific Overrides -========================= - -Each runner may support additional options related to flashing. For -example, some runners support an ``--erase`` flag, which mass-erases -the flash storage on your board before flashing the Zephyr image. - -To view all of the available options for the runners your board -supports, as well as their usage information, use ``--context`` (or -``-H``):: - - west flash --context - -.. important:: - - Note the capital H in the short option name. This re-runs the build - in order to ensure the information displayed is up to date! - -When running West outside of a build directory, ``west flash -H`` just -prints a list of runners. You can use ``west flash -H -r -`` to print usage information for options supported by -that runner. - -For example, to print usage information about the ``jlink`` runner:: - - west flash -H -r jlink - -.. _west-multi-domain-flashing: - -Multi-domain flashing -===================== - -When a :ref:`west-multi-domain-builds` folder is detected, then ``west flash`` -will flash all domains in the order defined by sysbuild. - -It is possible to flash the image from a single domain in a multi-domain project -by using ``--domain``. - -For example, in a multi-domain build with :zephyr:code-sample:`hello_world` and -`MCUboot`_, you can use the ``--domain hello_world`` domain to only flash -only the image from this domain:: - - west flash --domain hello_world - -.. _west-debugging: - -Configuration Options -===================== - -You can :ref:`configure ` ``west flash`` using these options. - -.. NOTE: docs authors: keep this table sorted alphabetically - -.. list-table:: - :widths: 10 30 - :header-rows: 1 - - * - Option - - Description - * - ``flash.rebuild`` - - Boolean, default ``true``. If ``false``, do not rebuild on west flash. - -Debugging: ``west debug``, ``west debugserver`` -*********************************************** - -.. tip:: - - Run ``west debug -h`` or ``west debugserver -h`` for additional help. - -Basics -====== - -From a Zephyr build directory, to attach a debugger to your board and -open up a debug console (e.g. a GDB session):: - - west debug - -To attach a debugger to your board and open up a local network port -you can connect a debugger to (e.g. an IDE debugger):: - - west debugserver - -Without options, the behavior is the same as ``ninja debug`` and -``ninja debugserver`` (or ``make debug``, etc.). - -To specify the build directory, use ``--build-dir`` (or ``-d``):: - - west debug --build-dir path/to/build/directory - west debugserver --build-dir path/to/build/directory - -If you don't specify the build directory, these commands search for one in -:file:`build`, then the current working directory. If you set the -``build.dir-fmt`` configuration option (see :ref:`west-building-dirs`), ``west -debug`` searches there instead of :file:`build`. - -Choosing a Runner -================= - -If your board's Zephyr integration supports debugging with multiple -programs, you can specify which one to use using the ``--runner`` (or -``-r``) option. For example, if West debugs your board with -``pyocd-gdbserver`` by default, but it also supports JLink, you can -override the default with:: - - west debug --runner jlink - west debugserver --runner jlink - -See :ref:`west-runner` below for more information on the ``runner`` -library used by West. The list of runners which support debugging can -be obtained with ``west debug -H``; if run from a build directory or -with ``--build-dir``, this will print additional information on -available runners for your board. - -Configuration Overrides -======================= - -The CMake cache contains default values West uses for debugging, such -as where the board directory is on the file system, the path to the -zephyr binaries containing symbol tables, and more. You can override -any of this configuration at runtime with additional options. - -For example, to override the ELF file containing the Zephyr binary and -symbol tables (assuming your runner expects an ELF file), but keep -other debug configuration at default values:: - - west debug --elf-file path/to/some/other.elf - west debugserver --elf-file path/to/some/other.elf - -The ``west debug -h`` output includes a complete list of overrides -supported by all runners. - -Runner-Specific Overrides -========================= - -Each runner may support additional options related to debugging. For -example, some runners support flags which allow you to set the network -ports used by debug servers. - -To view all of the available options for the runners your board -supports, as well as their usage information, use ``--context`` (or -``-H``):: - - west debug --context - -(The command ``west debugserver --context`` will print the same output.) - -.. important:: - - Note the capital H in the short option name. This re-runs the build - in order to ensure the information displayed is up to date! - -When running West outside of a build directory, ``west debug -H`` just -prints a list of runners. You can use ``west debug -H -r -`` to print usage information for options supported by -that runner. - -For example, to print usage information about the ``jlink`` runner:: - - west debug -H -r jlink - -.. _west-multi-domain-debugging: - -Multi-domain debugging -====================== - -``west debug`` can only debug a single domain at a time. When a -:ref:`west-multi-domain-builds` folder is detected, ``west debug`` -will debug the ``default`` domain specified by sysbuild. - -The default domain will be the application given as the source directory. -See the following example:: - - west build --sysbuild path/to/source/directory - -For example, when building ``hello_world`` with `MCUboot`_ using sysbuild, -``hello_world`` becomes the default domain:: - - west build --sysbuild samples/hello_world - -So to debug ``hello_world`` you can do:: - - west debug - -or:: - - west debug --domain hello_world - -If you wish to debug MCUboot, you must explicitly specify MCUboot as the domain -to debug:: - - west debug --domain mcuboot - -.. _west-runner: - -Configuration Options -===================== - -You can :ref:`configure ` ``west debug`` and -:ref:`configure ` ``west debugserver`` using these options. - -.. NOTE: docs authors: keep this table sorted alphabetically - -.. list-table:: - :widths: 10 30 - :header-rows: 1 - - * - Option - - Description - * - ``debug.rebuild`` - - Boolean, default ``true``. If ``false``, do not rebuild on west debug. - * - ``debugserver.rebuild`` - - Boolean, default ``true``. If ``false``, do not rebuild on west debugserver. - -Flash and debug runners -*********************** - -The flash and debug commands use Python wrappers around various -:ref:`flash-debug-host-tools`. These wrappers are all defined in a Python -library at :zephyr_file:`scripts/west_commands/runners`. Each wrapper is -called a *runner*. Runners can flash and/or debug Zephyr programs. - -The central abstraction within this library is ``ZephyrBinaryRunner``, an -abstract class which represents runners. The set of available runners is -determined by the imported subclasses of ``ZephyrBinaryRunner``. -``ZephyrBinaryRunner`` is available in the ``runners.core`` module; individual -runner implementations are in other submodules, such as ``runners.nrfjprog``, -``runners.openocd``, etc. - -Running Robot Framework tests: ``west robot`` -********************************************* - -.. tip:: Run ``west robot -h`` for additional help. - -Basics -====== - -Currently the command supports only one runner which is using ``renode-test``, -(essentially a wrapper for running Robot tests in Renode), but can be -easily extended by adding other runners. - -From a Zephyr build directory, to run a Robot test suite:: - - west robot --runner=renode-robot --testsuite path/to/testsuite.robot - -This will run all tests from testsuite.robot and print output provided -by Robot Framework. - -To pass additional parameters to Renode use ``--renode-robot-args`` switch. -For example to show Renode logs in addition to Robot Framework's output: - - west robot --runner=renode-robot --testsuite path/to/testsuite.robot --renode-robot-arg="--show-log" - -Runner-Specific Overrides -========================= - -To view all of the available options for the Robot runners your board -supports, as well as their usage information, use ``--context`` (or -``-H``):: - - west robot --runner=renode-robot --context - - -To view all available options "renode-test" runner supports, use:: - - west robot --runner=renode-robot --renode-robot-help - -Simulating a board with: ``west simulate`` -****************************************** - -Basics -====== - -Currently the command supports only one runner which is using Renode, -but can be easily extended by adding other runners. - -From a Zephyr build directory, to run the built binary:: - - west simulate --runner=renode - -This will start Renode and configure simulation based on a default ``.resc`` script -for the current platform with the zephyr.elf file loaded by default. The simulation -then can be started by typing "start" or "s" in Renode's Monitor. This can also be -done by passing a command to Renode, using an argument provided by the runner: - - west simulate --runner=renode --renode-command start - -To pass an argument to Renode itself, for example to start Renode in console mode -instead of a separate window: - - west simulate --runner=renode --renode-arg="--console" - -From that point on Renode can be used normally in both console and window modes. -For details on using Renode see `Renode - documentation`_. - -.. _Renode - documentation: - https://docs.renode.io - -Runner-Specific Overrides -========================= - -To view all of the available options supported by the runners, as well -as their usage information, use ``--context`` (or ``-H``):: - - west simulate --runner=renode --context - -To view all available options Renode supports, use:: - - west simulate --runner=renode --renode-help - -Out of tree runners -******************* - -:ref:`Zephyr modules ` can have external runners discovered by adding python -files in their :ref:`module.yml `. Create an external runner class by -inheriting from ``ZephyrBinaryRunner`` and implement all abstract methods. - -.. note:: - - Support for custom out-of-tree runners makes the ``runners.core`` module part of - the public API and backwards incompatible changes need to undergo the - :ref:`deprecation process `. - -Hacking -******* - -This section documents the ``runners.core`` module used by the -flash and debug commands. This is the core abstraction used to implement -support for these features. - -Developers can add support for new ways to flash and debug Zephyr programs by -implementing additional runners. To get this support into upstream Zephyr, the -runner should be added into a new or existing ``runners`` module, and imported -from :file:`runners/__init__.py`. - -.. note:: - - The test cases in :zephyr_file:`scripts/west_commands/tests` add unit test - coverage for the runners package and individual runner classes. - - Please try to add tests when adding new runners. Note that if your - changes break existing test cases, CI testing on upstream pull - requests will fail. - -.. automodule:: runners.core - :members: - -Doing it By Hand -**************** - -If you prefer not to use West to flash or debug your board, simply -inspect the build directory for the binaries output by the build -system. These will be named something like ``zephyr/zephyr.elf``, -``zephyr/zephyr.hex``, etc., depending on your board's build system -integration. These binaries may be flashed to a board using -alternative tools of your choice, or used for debugging as needed, -e.g. as a source of symbol tables. - -By default, these West commands rebuild binaries before flashing and -debugging. This can of course also be accomplished using the usual -targets provided by Zephyr's build system (in fact, that's how these -commands do it). - -.. _cmake(1): - https://cmake.org/cmake/help/latest/manual/cmake.1.html - -.. _CMAKE_VERBOSE_MAKEFILE: - https://cmake.org/cmake/help/latest/variable/CMAKE_VERBOSE_MAKEFILE.html - -.. _CMake Generator: - https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html - -.. _MCUboot: https://mcuboot.com/ diff --git a/doc/index.rst b/doc/index.rst index 0ad4cade..6b37d00b 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -39,11 +39,7 @@ each command. config.rst alias.rst extensions.rst - build-flash-debug.rst - sign.rst - zephyr-cmds.rst why.rst - without-west.rst For details on west's Python APIs, see :ref:`west-apis`. diff --git a/doc/sign.rst b/doc/sign.rst deleted file mode 100644 index b2d85367..00000000 --- a/doc/sign.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. _west-sign: - -Signing Binaries -################ - -The ``west sign`` :ref:`extension ` command can be used to -sign a Zephyr application binary for consumption by a bootloader using an -external tool. In some configurations, ``west sign`` is also used to invoke -an external, post-processing tool that "stitches" the final components of -the image together. Run ``west sign -h`` for command line help. - -rimage -****** - -rimage configuration uses an approach that does not rely on Kconfig or CMake -but on :ref:`west config`, similar to -:ref:`west-building-cmake-config`. - -Signing involves a number of "wrapper" scripts stacked on top of each other: ``west -flash`` invokes ``west build`` which invokes ``cmake`` and ``ninja`` which invokes -``west sign`` which invokes ``imgtool`` or `rimage`_. As long as the signing -parameters desired are the default ones and fairly static, these indirections are -not a problem. On the other hand, passing ``imgtool`` or ``rimage`` options through -all these layers can causes issues typical when the layers don't abstract -anything. First, this usually requires boilerplate code in each layer. Quoting -whitespace or other special characters through all the wrappers can be -difficult. Reproducing a lower ``west sign`` command to debug some build-time issue -can be very time-consuming: it requires at least enabling and searching verbose -build logs to find which exact options were used. Copying these options from the -build logs can be unreliable: it may produce different results because of subtle -environment differences. Last and worst: new signing feature and options are -impossible to use until more boilerplate code has been added in each layer. - -To avoid these issues, ``rimage`` parameters can bet set in ``west config``. -Here's a ``workspace/.west/config`` example: - -.. code-block:: ini - - [sign] - # Not needed when invoked from CMake - tool = rimage - - [rimage] - # Quoting is optional and works like in Unix shells - # Not needed when rimage can be found in the default PATH - path = "/home/me/zworkspace/build-rimage/rimage" - - # Not needed when using the default development key - extra-args = -i 4 -k 'keys/key argument with space.pem' - -In order to support quoting, values are parsed by Python's ``shlex.split()`` like in -:ref:`west-building-cmake-args`. - -The ``extra-args`` are passed directly to the ``rimage`` command. The example -above has the same effect as appending them on command line after ``--`` like this: -``west sign --tool rimage -- -i 4 -k 'keys/key argument with space.pem'``. In case -both are used, the command-line arguments go last. - -.. _rimage: - https://github.com/thesofproject/rimage - - -silabs_commander -**************** - -The ``silabs_commander`` tool is used to apply sign or MIC or encrypt binaries for Silicon Labs -devices. It can be invoked either by ``west sign`` when the ``sign.tool`` configuration is set to -``silabs_commander`` or by ``west build`` if ``CONFIG_SIWX91X_SIGN_KEY`` or -``CONFIG_SIWX91X_MIC_KEY`` is set. - -If one of ``CONFIG_SIWX91X_SIGN_KEY`` or ``CONFIG_SIWX91X_MIC_KEY`` is set, ``west flash`` will -automatically flash the signed version of the binary. - -``silabs_commander`` require `Simplicity Commander`_ to be install on the host. The provisionning of the -key on the device is described in `UG574 SiWx917 SoC Manufacturing Utility User Guide`_. - -.. _Simplicity Commander: - https://www.silabs.com/developer-tools/simplicity-studio/simplicity-commander?tab=downloads -.. _UG574 SiWx917 SoC Manufacturing Utility User Guide: - https://www.silabs.com/documents/public/user-guides/ug574-siwx917-soc-manufacturing-utility-user-guide.pdf diff --git a/doc/west-not-found.rst b/doc/west-not-found.rst deleted file mode 100644 index 27f48e3d..00000000 --- a/doc/west-not-found.rst +++ /dev/null @@ -1,16 +0,0 @@ -:orphan: - -.. _west-apis: -.. _west-apis-west: -.. _west-apis-commands: -.. _west-apis-westcommand: -.. _west-apis-configuration: -.. _west-apis-log: -.. _west-apis-manifest: -.. _west-apis-util: - -West APIs -######### - -The west APIs are not documented since either west was missing or the zephyr -repository was not initialized using west during the documentation build. diff --git a/doc/without-west.rst b/doc/without-west.rst deleted file mode 100644 index 8679e1c8..00000000 --- a/doc/without-west.rst +++ /dev/null @@ -1,128 +0,0 @@ -.. _no-west: - -Using Zephyr without west -######################### - -This page provides information on using Zephyr without west. This is -not recommended for beginners due to the extra effort involved. In -particular, you will have to do work "by hand" to replace these -features: - -- cloning the additional source code repositories used by Zephyr in - addition to the main zephyr repository, and keeping them up to date -- specifying the locations of these repositories to the Zephyr build - system -- flashing and debugging without understanding detailed usage of the - relevant host tools - -.. note:: - - If you have previously installed west and want to stop using it, - uninstall it first: - - .. code-block:: console - - pip3 uninstall west - - Otherwise, Zephyr's build system will find it and may try to use - it. - -Getting the Source ------------------- - -In addition to downloading the zephyr source code repository itself, -you will need to manually clone the additional projects listed in the -:term:`west manifest` file inside that repository. - -.. code-block:: console - - mkdir zephyrproject - cd zephyrproject - git clone https://github.com/zephyrproject-rtos/zephyr - # clone additional repositories listed in zephyr/west.yml, - # and check out the specified revisions as well. - -As you pull changes in the zephyr repository, you will also need to -maintain those additional repositories, adding new ones as necessary -and keeping existing ones up to date at the latest revisions. - -Building applications ---------------------- - -You can build a Zephyr application using CMake and Ninja (or make) directly -without west installed if you specify any modules manually. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :tool: cmake - :goals: build - :gen-args: -DZEPHYR_MODULES=module1;module2;... - :compact: - -When building with west installed, the Zephyr build system will use it to set -:ref:`ZEPHYR_MODULES `. - -If you don't have west installed and your application does not need any of -these repositories, the build will still work. - -If you don't have west installed and your application *does* need one -of these repositories, you must set :makevar:`ZEPHYR_MODULES` -yourself as shown above. - -See :ref:`modules` for more details. - -Similarly, if your application requires binary blobs and you are not using -west, you will need to download and place those blobs in the right places -instead of using ``west blobs``. See :ref:`bin-blobs` for more details. - -Flashing and Debugging ----------------------- - -Running build system targets like ``ninja flash``, ``ninja debug``, -etc. is just a call to the corresponding :ref:`west command -`. For example, ``ninja flash`` calls ``west -flash``\ [#wbninja]_. If you don't have west installed on your system, running -those targets will fail. You can of course still flash and debug using -any :ref:`flash-debug-host-tools` which work for your board (and which those -west commands wrap). - -If you want to use these build system targets but do not want to -install west on your system using ``pip``, it is possible to do so -by manually creating a :term:`west workspace`: - -.. code-block:: console - - # cd into zephyrproject if not already there - git clone https://github.com/zephyrproject-rtos/west.git .west/west - -Then create a file :file:`.west/config` with the following contents: - -.. code-block:: none - - [manifest] - path = zephyr - - [zephyr] - base = zephyr - -After that, and in order for ``ninja`` to be able to invoke ``west`` -to flash and debug, you must specify the west directory. This can be -done by setting the environment variable ``WEST_DIR`` to point to -:file:`zephyrproject/.west/west` before running CMake to set up a -build directory. - -.. rubric:: Footnotes - -.. [#wbninja] - - Note that ``west build`` invokes ``ninja``, among other - tools. There's no recursive invocation of either ``west`` or - ``ninja`` involved by default, however, as ``west build`` does not - invoke ``ninja flash``, ``debug``, etc. The one exception is if you - specifically run one of these build system targets with a command - line like ``west build -t flash``. In that case, west is run twice: - once for ``west build``, and in a subprocess, again for ``west - flash``. Even in this case, ``ninja`` is only run once, as ``ninja - flash``. This is because these build system targets depend on an - up to date build of the Zephyr application, so it's compiled before - ``west flash`` is run. diff --git a/doc/zephyr-cmds.rst b/doc/zephyr-cmds.rst deleted file mode 100644 index 47e17390..00000000 --- a/doc/zephyr-cmds.rst +++ /dev/null @@ -1,434 +0,0 @@ -.. _west-zephyr-ext-cmds: - -Additional Zephyr extension commands -#################################### - -This page documents miscellaneous :ref:`west-zephyr-extensions`. - -.. _west-boards: - -Listing boards: ``west boards`` -******************************* - -The ``boards`` command can be used to list the boards that are supported by -Zephyr without having to resort to additional sources of information. - -It can be run by typing:: - - west boards - -This command lists all supported boards in a default format. If you prefer to -specify the display format yourself you can use the ``--format`` (or ``-f``) -flag:: - - west boards -f "{arch}:{name}" - -Additional help about the formatting options can be found by running:: - - west boards -h - -.. _west-completion: - -Shell completion scripts: ``west completion`` -********************************************* - -The ``completion`` extension command outputs shell completion scripts that can -then be used directly to enable shell completion for the supported shells. - -It currently supports the following shells: - -- bash -- zsh -- fish -- powershell (board qualifiers only) - -Additional instructions are available in the command's help:: - - west help completion - -.. _west-zephyr-export: - -Installing CMake packages: ``west zephyr-export`` -************************************************* - -This command registers the current Zephyr installation as a CMake -config package in the CMake user package registry. - -In Windows, the CMake user package registry is found in -``HKEY_CURRENT_USER\Software\Kitware\CMake\Packages``. - -In Linux and MacOS, the CMake user package registry is found in. -:file:`~/.cmake/packages`. - -You may run this command when setting up a Zephyr workspace. If you do, -application CMakeLists.txt files that are outside of your workspace will be -able to find the Zephyr repository with the following: - -.. code-block:: cmake - - find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) - -See :zephyr_file:`share/zephyr-package/cmake` for details. - -.. _west-spdx: - -Software bill of materials: ``west spdx`` -***************************************** - -This command generates SPDX 2.2 or 2.3 tag-value documents, creating relationships -from source files to the corresponding generated build files. -``SPDX-License-Identifier`` comments in source files are scanned and filled -into the SPDX documents. - -To use this command: - -#. Pre-populate a build directory :file:`BUILD_DIR` like this: - - .. code-block:: bash - - west spdx --init -d BUILD_DIR - - This step ensures the build directory contains CMake metadata required for - SPDX document generation. - -#. Enable :file:`CONFIG_BUILD_OUTPUT_META` in your project. - -#. Build your application using this pre-created build directory, like so: - - .. code-block:: bash - - west build -d BUILD_DIR [...] - -#. Generate SPDX documents using this build directory: - - .. code-block:: bash - - west spdx -d BUILD_DIR - - By default, this generates SPDX 2.3 documents. To generate SPDX 2.2 documents instead: - - .. code-block:: bash - - west spdx -d BUILD_DIR --spdx-version 2.2 - -.. note:: - - When building with :ref:`sysbuild`, make sure you target the actual application - which you want to generate the SBOM for. For example, if the application is - named ``hello_world``: - - .. code-block:: bash - - west spdx --init -d BUILD_DIR/hello_world - west build -d BUILD_DIR/hello_world - west spdx -d BUILD_DIR/hello_world - -This generates the following SPDX bill-of-materials (BOM) documents in -:file:`BUILD_DIR/spdx/`: - -- :file:`app.spdx`: BOM for the application source files used for the build -- :file:`zephyr.spdx`: BOM for the specific Zephyr source code files used for the build -- :file:`build.spdx`: BOM for the built output files -- :file:`modules-deps.spdx`: BOM for modules dependencies. Check - :ref:`modules ` for more details. - -Each file in the bill-of-materials is scanned, so that its hashes (SHA256 and -SHA1) can be recorded, along with any detected licenses if an -``SPDX-License-Identifier`` comment appears in the file. - -Copyright notices are extracted using the third-party :command:`reuse` tool from the REUSE group. -When found, these notices are added to SPDX documents as ``FileCopyrightText`` fields. - -.. note:: - Copyright extraction uses heuristics that may not capture complete notice text, so - ``FileCopyrightText`` content is best-effort. This aligns with SPDX specification recommendations. - -SPDX Relationships are created to indicate dependencies between -CMake build targets, build targets that are linked together, and -source files that are compiled to generate the built library files. - -``west spdx`` accepts these additional options: - -- ``-n PREFIX``: a prefix for the Document Namespaces that will be included in - the generated SPDX documents. See `SPDX specification clause 6`_ for - details. If ``-n`` is omitted, a default namespace will be generated - according to the default format described in section 2.5 using a random UUID. - -- ``-s SPDX_DIR``: specifies an alternate directory where the SPDX documents - should be written instead of :file:`BUILD_DIR/spdx/`. - -- ``--spdx-version {2.2,2.3}``: specifies which SPDX specification version to use. - Defaults to ``2.3``. SPDX 2.3 includes additional fields like ``PrimaryPackagePurpose`` - that are not available in SPDX 2.2. - -- ``--analyze-includes``: in addition to recording the compiled source code - files (e.g. ``.c``, ``.S``) in the bills-of-materials, also attempt to - determine the specific header files that are included for each ``.c`` file. - - This takes longer, as it performs a dry run using the C compiler for each - ``.c`` file using the same arguments that were passed to it for the actual - build. - -- ``--include-sdk``: with ``--analyze-includes``, also create a fourth SPDX - document, :file:`sdk.spdx`, which lists header files included from the SDK. - -.. warning:: - - The generation of SBOM documents for the ``native_sim`` platform is currently not supported. - -.. _SPDX specification clause 6: - https://spdx.github.io/spdx-spec/v2.2.2/document-creation-information/ - -.. _west-blobs: - -Working with binary blobs: ``west blobs`` -***************************************** - -The ``blobs`` command allows users to interact with :ref:`binary blobs -` declared in one or more :ref:`modules ` via their -:ref:`module.yml ` file. - -The ``blobs`` command has three sub-commands, used to list, fetch or clean (i.e. -delete) the binary blobs themselves. - -You can list binary blobs while specifying the format of the output:: - - west blobs list -f '{module}: {type} {path}' - -For the full set of variables available in ``-f/--format`` run -``west blobs -h``. - -Fetching blobs works in a similar manner:: - - west blobs fetch - -Note that, as described in :ref:`the modules section `, -fetched blobs are stored in a :file:`zephyr/blobs/` folder relative to the root -of the corresponding module repository. - -As does deleting them:: - - west blobs clean - -Additionally the tool allows you to specify the modules you want to list, -fetch or clean blobs for by typing the module names as a command-line -parameter. - -The argument ``--allow-regex`` can be passed ``west blobs fetch`` to restrict -the specific blobs that are fetched, by passing a regular expression:: - - # For example, only download esp32 blobs, skip the other variants - west blobs fetch hal_espressif --allow-regex 'lib/esp32/.*' - -.. _west-twister: - -Twister wrapper: ``west twister`` -********************************* -This command is a wrapper for :ref:`twister `. - -Twister can then be invoked via west as follows:: - - west twister -help - west twister -T tests/ztest/base - -.. _west-bindesc: - -Working with binary descriptors: ``west bindesc`` -************************************************* - -The ``bindesc`` command allows users to read :ref:`binary descriptors` -of executable files. It currently supports ``.bin``, ``.hex``, ``.elf`` and ``.uf2`` files -as input. - -You can search for a specific descriptor in an image, for example:: - - west bindesc search KERNEL_VERSION_STRING build/zephyr/zephyr.bin - -You can search for a custom descriptor by type and ID, for example:: - - west bindesc custom_search STR 0x200 build/zephyr/zephyr.bin - -You can dump all of the descriptors in an image using:: - - west bindesc dump build/zephyr/zephyr.bin - -You can extract the descriptor data area of the image to a file using:: - - west bindesc extract - -You can list all known standard descriptor names using:: - - west bindesc list - -You can print the offset of the descriptors inside the image using:: - - west bindesc get_offset - -Indexing the sources with GNU Global: ``west gtags`` -**************************************************** - -.. important:: You must install the ``gtags`` and ``global`` programs provided - by `GNU Global`_ to use this command. - -The ``west gtags`` command lets you create a GNU Global tags file for the entire -west workspace:: - - west gtags - -.. _GNU Global: https://www.gnu.org/software/global/ - -This will create a tags file named ``GTAGS`` in the workspace :ref:`topdir -` (it will also create other Global-related metadata files -named ``GPATH`` and ``GRTAGS`` in the same place). - -You can then run the ``global`` command anywhere inside the -workspace to search for symbol locations using this tags file. - -For example, to search for definitions of the ``arch_system_halt()`` function, -starting from the ``zephyr/drivers`` directory:: - - $ cd zephyr/drivers - $ global -x arch_system_halt - arch_system_halt 65 ../arch/arc/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) - arch_system_halt 455 ../arch/arm64/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) - arch_system_halt 137 ../arch/nios2/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) - arch_system_halt 18 ../arch/posix/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) - arch_system_halt 17 ../arch/x86/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) - arch_system_halt 126 ../arch/xtensa/core/fatal.c FUNC_NORETURN void arch_system_halt(unsigned int reason) - arch_system_halt 21 ../kernel/fatal.c FUNC_NORETURN __weak void arch_system_halt(unsigned int reason) - -This prints the search symbol, the line it is defined on, a relative path to -the file it is defined in, and the line itself, for all places where the symbol -is defined. - -Additional tips: - -- This can also be useful to search for vendor HAL function definitions. - -- See the ``global`` command's manual page for more information on how to use - this tool. - -- You should run ``global``, **not** ``west global``. There is no need for a - separate ``west global`` command since ``global`` already searches for the - ``GTAGS`` file starting from your current working directory. This is why you - need to run ``global`` from inside the workspace. - -.. _west-patch: - -Working with patches: ``west patch`` -************************************ - -The ``patch`` command allows users to apply patches to Zephyr or Zephyr modules -in a controlled manner that makes automation and tracking easier for external applications that -use the :ref:`T2 star topology `. The :ref:`patches.yml ` file stores -metadata about patch files and fills-in the gaps between official Zephyr releases, so that users -can easily see the status of any upstreaming efforts, and determine which patches to drop before -upgrading to the next Zephyr release. - -There are several sub-commands available to manage patches for Zephyr or other modules in the -workspace: - -* ``apply``: apply patches listed in ``patches.yml`` -* ``clean``: remove all patches that have been applied, and reset to the manifest checkout state -* ``list``: list all patches in ``patches.yml`` -* ``gh-fetch``: fetch patches from a GitHub pull request - -.. code-block:: none - - west-workspace/ - └── application/ - ... - ├── west.yml - └── zephyr - ├── module.yml - ├── patches - │ ├── bootloader - │ │ └── mcuboot - │ │ └── my-tweak-for-mcuboot.patch - │ └── zephyr - │ └── my-zephyr-change.patch - └── patches.yml - -In this example, the :ref:`west manifest ` file, ``west.yml``, would pin to a -specific Zephyr revision (e.g. ``v4.1.0``) and apply patches against that revision of Zephyr and -the specific revisions of other modules used in the application. However, this application needs -two changes in order to meet requirements; one for Zephyr and another for MCUBoot. - -.. _patches-yml: - -.. code-block:: yaml - - patches: - - path: zephyr/my-zephyr-change.patch - sha256sum: c676cd376a4d19dc95ac4e44e179c253853d422b758688a583bb55c3c9137035 - module: zephyr - author: Obi-Wan Kenobi - email: obiwan@jedi.org - date: 2025-05-04 - upstreamable: false - comments: | - An application-specific change we need for Zephyr. - - path: bootloader/mcuboot/my-tweak-for-mcuboot.patch - sha256sum: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 - module: mcuboot - author: Darth Sidious - email: sidious@sith.org - date: 2025-05-04 - merge-pr: https://github.com/zephyrproject-rtos/zephyr/pull/ - issue: https://github.com/zephyrproject-rtos/zephyr/issues/ - merge-status: true - merge-commit: 1234567890abcdef1234567890abcdef12345678 - merge-date: 2025-05-06 - apply-command: git apply - comments: | - A change to mcuboot that has been merged already. We can remove this - patch when we are ready to upgrade to the next Zephyr release. - -Patches can easily be applied in an automated manner. For example: - -.. code-block:: bash - - west init -m - cd - west update - west patch apply - -When it is time to update to a newer version of Zephyr, the ``west.yml`` file can be updated to -point at the next Zephyr release, e.g. ``v4.2.0``. Patches that are no longer needed, like -``my-tweak-for-mcuboot.patch`` in the example above, can be removed from ``patches.yml`` and from -the external application repository, and then the following commands can be run. - -.. code-block:: bash - - west patch clean - west update - west patch apply --roll-back # roll-back all patches if one does not apply cleanly - -If a patch needs to be reworked, remember to update the ``patches.yml`` file with the new SHA256 -checksum. - -.. code-block:: bash - - sha256sum zephyr/patches/zephyr/my-zephyr-change.patch - 7d57ca78d5214f422172cc47fed9d0faa6d97a0796c02485bff0bf29455765e9 - -It is also possible to use ``west patch gh-fetch`` to fetch patches from a GitHub pull request and -automatically create or update the ``patches.yml`` file. This can be useful when the author already -has a number of changes captured in existing upstream pull requests. - -.. code-block:: bash - - west patch gh-fetch --owner zephyrproject-rtos --repo zephyr --pull-request \ - --module zephyr --split-commits - -The above command will create the directory and file structure below, which includes patches for -each individual commit associated with the given pull request. - -.. code-block:: none - - zephyr - ├── patches - │ ├── first-commit-from-pr.patch - │ ├── second-commit-from-pr.patch - │ └── third-commit-from-pr.patch - └── patches.yml From 4e6bf64d0fd31cea3c2648c28842f2912f5859d5 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 6 Nov 2025 20:08:36 +0100 Subject: [PATCH 224/226] doc: Add sphinx conf.py and static resources Add necessary sphinx files to build the West documentation. Signed-off-by: Pieter De Gendt --- .gitignore | 1 + doc/_static/css/custom.css | 1119 +++++++++++++++++ doc/_static/css/dark.css | 98 ++ doc/_static/css/gcs.css | 101 ++ doc/_static/css/light.css | 96 ++ doc/_static/images/logo.png | Bin 0 -> 73757 bytes doc/_static/images/west-mr-model.png | Bin 0 -> 67684 bytes doc/_static/js/custom.js | 122 ++ ...dark-mode-toggle-stylesheets-loader.min.js | 2 + doc/_static/js/dark-mode-toggle.min.mjs | 2 + doc/_templates/breadcrumbs.html | 34 + doc/_templates/footer.html | 18 + doc/_templates/gsearch.html | 17 + doc/_templates/layout.html | 41 + doc/_templates/searchbox.html | 131 ++ doc/_templates/versions.html | 1 + doc/_templates/zversions.html | 33 + doc/conf.py | 59 + 18 files changed, 1875 insertions(+) create mode 100644 doc/_static/css/custom.css create mode 100644 doc/_static/css/dark.css create mode 100644 doc/_static/css/gcs.css create mode 100644 doc/_static/css/light.css create mode 100644 doc/_static/images/logo.png create mode 100644 doc/_static/images/west-mr-model.png create mode 100644 doc/_static/js/custom.js create mode 100644 doc/_static/js/dark-mode-toggle-stylesheets-loader.min.js create mode 100644 doc/_static/js/dark-mode-toggle.min.mjs create mode 100644 doc/_templates/breadcrumbs.html create mode 100644 doc/_templates/footer.html create mode 100644 doc/_templates/gsearch.html create mode 100644 doc/_templates/layout.html create mode 100644 doc/_templates/searchbox.html create mode 100644 doc/_templates/versions.html create mode 100644 doc/_templates/zversions.html create mode 100644 doc/conf.py diff --git a/.gitignore b/.gitignore index 7e40b86a..36026deb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ htmlcov/ .dir-locals.el .venv/ junit.xml +doc/_build/ diff --git a/doc/_static/css/custom.css b/doc/_static/css/custom.css new file mode 100644 index 00000000..2d365419 --- /dev/null +++ b/doc/_static/css/custom.css @@ -0,0 +1,1119 @@ +/** + * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community + * Copyright (c) 2021, Teslabs Engineering S.L. + * Copyright (c) 2023-2025, The Linux Foundation. + * SPDX-License-Identifier: CC-BY-3.0 + * + * Various tweaks to the Read the Docs theme to better conform with Zephyr's + * visual identity. Many colors are also overridden to use CSS variables. + */ + + :root { + /* Use system font stacks for better performance (no Web fonts required) */ + --system-font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --header-font-family: Seravek, 'Gill Sans Nova', Ubuntu, Calibri, 'DejaVu Sans', source-sans-pro, sans-serif; + --monospace-font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Mono', 'Droid Sans Mono', 'Source Code Pro', monospace; + } + +body, +h1, +h2, +h3, +h4, +h5, +h6, +input[type="text"], +input[type="button"], +input[type="reset"], +input[type="submit"], +textarea, +legend, +.btn, +.rst-content .toctree-wrapper p.caption, +.rst-versions { + font-family: var(--system-font-family); +} + +h1, +h2, +h3, +h4, +h5, +h6, +legend, +.rst-content .toctree-wrapper p.caption { + /* Use a lighter font for headers (Semi-Bold instead of Bold) */ + font-weight: 600; + font-family: var(--header-font-family); +} + +.rst-content div.figure p.caption { + /* Tweak caption styling to be closer to typical captions */ + text-align: center; + margin-top: 8px; + opacity: 0.75; +} + +.rst-content div.figure.figure-w480 { + max-width: 480px; +} + +p, +article ul, +article ol, +.wy-plain-list-disc, +.wy-plain-list-decimal, +.rst-content ol.arabic, +.rst-content .section ul, +.rst-content .toctree-wrapper ul, +.rst-content .section ol { + /* Increase the line height slightly to account for the different font */ + line-height: 25px; +} + +body, +.rst-content table.docutils thead { + color: var(--body-color); +} + +a { + color: var(--link-color); +} + +a:hover { + color: var(--link-color-hover); + text-decoration: underline; +} + +a:active { + /* Add visual feedback when clicking on a link */ + color: var(--link-color-active); +} + +a:visited { + color: var(--link-color-visited); +} + +a.btn:hover { + text-decoration: none; +} + +.sphinx-tabs .sphinx-menu a.item { + /* Original definition has `!important` */ + color: var(--link-color) !important; +} + +.rst-content .toc-backref { + color: var(--link-color); +} + +/* Style external links differently to make them easier to distinguish from internal links. */ +.reference.external { + background-position: center right; + background-repeat: no-repeat; + background-image: var(--external-reference-icon); + padding-right: 13px; +} + +hr, +#search-results .search li:first-child, +#search-results .search li { + border-color: var(--hr-color); +} + +/* JavaScript documentation directives */ +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list) > dt { + background-color: var(--admonition-note-background-color); + border-color: var(--admonition-note-title-background-color); + color: var(--admonition-note-color); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl dt { + background-color: transparent; + border-color: transparent; + color: var(--footer-color); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).attribute dt { + font-weight: 600; + padding: 0 8px; + margin-bottom: 1px; + width: 100%; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class > dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function > dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method > dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).attribute > dt { + font-family: var(--monospace-font-family); + font-variant-ligatures: none; + font-size: 90%; + font-weight: normal; + margin-bottom: 16px; + padding: 6px 8px; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-prename.descclassname { + color: var(--highlight-type2-color); + font-weight: normal; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-name.descname { + color: var(--highlight-function-color); + font-weight: 700; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-paren, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional { + color: var(--highlight-operator-color) !important; + font-weight: normal; + padding: 0 2px; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional { + font-style: italic; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-param, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt > em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt > em { + color: var(--code-literal-color); + font-style: normal; + padding: 0 4px; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .k { + font-style: normal; +} +html.writer-html5 .rst-content dl:not(.docutils) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt { + border-top-color: var(--highlight-background-emph-color); + background: var(--highlight-background-color); +} +html.writer-html5 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt { + border-left-color: var(--highlight-background-emph-color); + background: var(--highlight-background-color); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-param, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > .optional ~ em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt > .optional ~ em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt > .optional ~ em { + color: var(--highlight-number-color); + font-style: italic; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > em.property { + color: var(--highlight-keyword-color); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt a.headerlink { + color: var(--link-color) !important; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt a.headerlink:visited { + color: var(--link-color-visited); +} +html.writer-html5 .rst-content dl.field-list > dd strong { + font-family: var(--monospace-font-family); + font-variant-ligatures: none; +} + +footer, +#search-results .context { + color: var(--footer-color); +} + +/* Icon tweaks */ +a.icon-home, +a.icon-home:visited { + color: var(--navbar-level-1-color); +} + +/* Main sections */ + +.wy-nav-content-wrap { + background-color: var(--content-wrap-background-color); +} + +.wy-nav-content { + background-color: var(--content-background-color); + min-height: 100vh; + min-height: 100dvh; + display: flex; +} + +.wy-body-for-nav { + background-color: var(--content-wrap-background-color); +} + +@media only screen and (min-width: 769px) { + .wy-nav-content { + max-width: 915px; + } +} + +/* Table display tweaks */ + +.rst-content table.docutils, +.wy-table-bordered-all td, +.rst-content table.docutils td, +.wy-table thead th, +.rst-content table.docutils thead th, +.rst-content table.field-list thead th { + border-color: var(--code-border-color); +} + +.rst-content table.docutils caption, .rst-content table.field-list caption, .wy-table caption { + color: var(--body-color); +} +.wy-table-odd td, +.wy-table-striped tr:nth-child(2n-1) td, +.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { + background-color: var(--table-row-odd-background-color); +} + +/* Override table no-wrap */ +/* The first column cells are not verbose, no need to wrap them */ +.wy-table-responsive table td:not(:nth-child(1)), +.wy-table-responsive table th:not(:nth-child(1)) { + white-space: normal; +} + +/* Allow to control wrapping behavior per table */ +.wy-table-responsive table.wrap-normal td, +.wy-table-responsive table.wrap-normal th { + white-space: normal; +} + +/* Make sure not to wrap keyboard shortcuts */ +.wy-table-responsive table td kbd { + white-space: nowrap; +} + +/* Force table content font-size in responsive tables to be 100% + * fixing larger font size for paragraphs in the kconfig tables */ + .wy-table-responsive td p { + font-size: 100%; +} + +/* Code display tweaks */ + +code, +.rst-content tt, +.rst-content code { + font-size: 14px; + background-color: var(--code-background-color); + border: 1px solid var(--code-border-color); +} + +.rst-content tt.literal, +.rst-content code.literal { + color: var(--code-literal-color); +} + +.rst-content div[class^="highlight"] { + border-color: none; + border: none; +} + +.rst-content pre.literal-block, +.rst-content div[class^="highlight"] pre, +.rst-content .linenodiv pre { + /* Increase the font size and line height in code blocks */ + font-size: 14px; + line-height: 1.5; +} + +.rst-content pre.literal-block { + border: none; + border-radius: 0.25rem; + background-color: var(--code-background-color); +} + +/* Code tab display tweaks */ + +.ui.tabular.menu .active.item, +.ui.segment, +.sphinx-tabs-panel { + background-color: var(--code-background-color) !important; +} + +.sphinx-tabs-tab { + color: var(--link-color) !important; +} + +.sphinx-tabs-tab[aria-selected="true"] { + background-color: var(--code-background-color) !important; + border-bottom: 1px solid var(--code-background-color) !important; +} + +/* Code literals */ +a.internal code.literal { + color: var(--link-color); +} + +a.internal:visited code.literal { + color: var(--link-color-visited); +} + +/* Syntax highlighting */ + +.tab div[class^='highlight']:last-child { + margin-bottom: 1em; +} + +.rst-content tt.literal, .rst-content code.literal, .highlight { + border-radius: 0.25rem; +} + +.highlight { + background-color: var(--highlight-background-color); +} + +/* Emphasized lines */ +.highlight .hll { + background-color: var(--highlight-background-emph-color); +} + +.highlight .gh /* Generic.Heading */, +.highlight .gu /* Generic.Subheading */, +.highlight .go /* Generic.Output */, +.highlight .gt /* Generic.Traceback */ { + color: var(--highlight-default-color); +} + +.highlight .c /* Comment */, +.highlight .c1 /* Comment.Single */, +.highlight .cm /* Comment.Multiline */, +.highlight .cs /* Comment.Special */ { + color: var(--highlight-comment-color); +} + +.highlight .bp /* Name.Builtin.Pseudo */, +.highlight .k /* Keyword */, +.highlight .kc /* Keyword.Constant */, +.highlight .kd /* Keyword.Declaration */, +.highlight .kn /* Keyword.Namespace */, +.highlight .kp /* Keyword.Pseudo */, +.highlight .kr /* Keyword.Reserved */, +.highlight .kt /* Keyword.Type */, +.highlight .ow /* Operator.Word */ { + color: var(--highlight-keyword-color); +} + +.highlight .ch /* Comment.Hashbang */, +.highlight .cp /* Comment.Preproc */ { + color: var(--highlight-keyword2-color); +} + +.highlight .m /* Literal.Number */, +.highlight .mf /* Literal.Number.Float */, +.highlight .mi /* Literal.Number.Integer */, +.highlight .il /* Literal.Number.Integer.Long */, +.highlight .mb /* Literal.Number.Bin */, +.highlight .mh /* Literal.Number.Hex */, +.highlight .mo /* Literal.Number.Oct */ { + color: var(--highlight-number-color); +} + +.highlight .na /* Name.Attribute */, +.highlight .nd /* Name.Decorator */, +.highlight .ni /* Name.Entity */, +.highlight .nl /* Name.Label */ { + color: var(--highlight-decorator-color); +} + +.highlight .nb /* Name.Builtin */, +.highlight .ne /* Name.Exception */ { + color: var(--highlight-type-color); +} + +.highlight .nc /* Name.Class */, +.highlight .nn /* Name.Namespace */, +.highlight .no /* Name.Constant */, +.highlight .nv /* Name.Variable */, +.highlight .vc /* Name.Variable.Class */, +.highlight .vg /* Name.Variable.Global */, +.highlight .vi /* Name.Variable.Instance */, +.highlight .vm /* Name.Variable.Magic */ { + color: var(--highlight-type2-color); +} + +.highlight .nf /* Name.Function */, +.highlight .fm /* Name.Function.Magic */, +.highlight .nt /* Name.Tag */ { + color: var(--highlight-function-color); +} + +.highlight .o /* Operator */, +.highlight .si /* Literal.String.Interpol */, +.highlight .sx /* Literal.String.Other */, +.highlight .sr /* Literal.String.Regex */, +.highlight .ss /* Literal.String.Symbol */ { + color: var(--highlight-operator-color); +} + +.highlight .cpf/* Comment.PreprocFile */, +.highlight .s /* Literal.String */, +.highlight .s1 /* Literal.String.Single */, +.highlight .s2 /* Literal.String.Double */, +.highlight .sc /* Literal.String.Char */, +.highlight .se /* Literal.String.Escape */, +.highlight .sa /* Literal.String.Affix */, +.highlight .sb /* Literal.String.Backtick */, +.highlight .dl /* Literal.String.Delimiter */, +.highlight .sd /* Literal.String.Doc */, +.highlight .sh /* Literal.String.Heredoc */ { + color: var(--highlight-string-color); +} + +/* Admonition tweaks */ + +.rst-content .admonition, +.rst-content .admonition.note, +.rst-content .admonition.seealso { + background-color: var(--admonition-note-background-color); + color: var(--admonition-note-color); + overflow: auto; +} + +.rst-content .admonition .admonition-title, +.rst-content .admonition.note .admonition-title, +.rst-content .admonition.seealso .admonition-title { + background-color: var(--admonition-note-title-background-color); + color: var(--admonition-note-title-color); +} + +.rst-content .admonition.attention, +.rst-content .admonition.caution, +.rst-content .admonition.warning { + background-color: var(--admonition-attention-background-color); + color: var(--admonition-attention-color); + overflow: auto; +} + +.rst-content .admonition.attention .admonition-title, +.rst-content .admonition.caution .admonition-title, +.rst-content .admonition.warning .admonition-title { + background-color: var(--admonition-attention-title-background-color); + color: var(--admonition-attention-title-color); +} + +.rst-content .admonition.danger { + background-color: var(--admonition-danger-background-color); + color: var(--admonition-danger-color); + overflow: auto; +} + +.rst-content .admonition.danger .admonition-title { + background-color: var(--admonition-danger-title-background-color); + color: var(--admonition-danger-title-color); +} + +.rst-content .admonition.tip, +.rst-content .admonition.important { + background-color: var(--admonition-tip-background-color); + color: var(--admonition-tip-color); + overflow: auto; +} + +.rst-content .admonition.tip .admonition-title, +.rst-content .admonition.important .admonition-title { + background-color: var(--admonition-tip-title-background-color); + color: var(--admonition-tip-title-color); +} + +/* Admonition tweaks - sphinx_togglebutton */ + +.rst-content .admonition.toggle { + overflow: visible; +} + +.rst-content .admonition.toggle button { + display: inline-flex; + color: var(--admonition-note-title-color); +} + +.rst-content .admonition.toggle .tb-icon { + height: 1em; + width: 1em; +} + +/* Keyboard shortcuts tweaks */ +kbd, .kbd, +.rst-content :not(dl.option-list) > :not(dt):not(kbd):not(.kbd) > kbd, +.rst-content :not(dl.option-list) > :not(dt):not(kbd):not(.kbd) > .kbd { + background-color: var(--kbd-background-color); + border: 1px solid var(--kbd-outline-color); + border-radius: 3px; + box-shadow: inset 0 -1px 0 var(--kbd-shadow-color); + color: var(--kbd-text-color); + display: inline-block; + font-size: 12px; + line-height: 11px; + padding: 4px 5px; + vertical-align: middle; +} + +/* guilabel and menuselection tweaks */ +.rst-content .guilabel, +.rst-content .menuselection { + color: var(--body-color); + background-color: var(--guiitems-background-color); + border-color: var(--guiitems-border-color); +} + +/* heading tweaks to make document hierarchy easier to grasp */ + +.rst-content section > h1 { + font-weight: 700; + margin-bottom: 2.5rem; + position: relative; + line-height: 1; + z-index: 1; +} + +.rst-content section > h1::before { + content: ''; + position: absolute; + z-index:-1; + left: 0; + right: 0; + height: 4px; + bottom: -1px; + background: linear-gradient(to right, var(--admonition-note-title-background-color), var(--admonition-note-title-background-color) 50%, var(--admonition-note-background-color) 80%, transparent); /* Example gradient */ + opacity:50%; +} + +.rst-content section > h2, +.rst-content section > h3, +.rst-content section > h4, +.rst-content section > h5 { + font-weight: 500; + padding-inline-start: 8px; + margin-inline-start: 0px; + border-inline-start: 8px solid; + padding-top: 0.2em; + padding-bottom: 0.2em; +} + +.rst-content section > h2 { + border-color: var(--admonition-note-title-background-color); +} + +.rst-content section > h3 { + border-color: var(--admonition-note-background-color); +} + +.rst-content section > h4 { + border-color: transparent; + font-weight: 400; +} + +.rst-content section > h5 { + border-color: transparent; + font-weight: 100; +} + +/* Buttons */ + +.btn-neutral { + background-color: var(--btn-neutral-background-color) !important; + color: var(--body-color) !important; +} + +.btn-neutral:hover { + background-color: var(--btn-neutral-hover-background-color) !important; +} + +.btn-neutral:visited { + color: var(--body-color) !important; +} + +/* Navigation bar logo and search */ + +.logo { + opacity: var(--logo-opacity); +} + +.wy-side-nav-search > a img.logo { + /* Fixed size to prevent reflows and support hiDPI displays */ + /* A 5 pixel margin is added on each side. The logo itself displays at 200×100 at 100% scaling. */ + width: 210px; + height: 105px; +} + +.wy-side-nav-search { + background-color: var(--navbar-background-color); +} + +.wy-side-nav-search.fixed { + position: fixed; +} + +@media only screen and (min-width: 769px) { + /* Simulate a drop shadow that only affects the bottom edge */ + /* This is used to indicate the search bar is fixed */ + .wy-side-nav-search.fixed-and-scrolled::after { + content: ''; + position: absolute; + left: 0; + bottom: -8px; + width: 300px; + height: 8px; + pointer-events: none; + background: linear-gradient(hsla(0, 0%, 0%, 0.2), transparent); + } +} + +.wy-side-nav-search > a:hover, +.wy-side-nav-search .wy-dropdown > a:hover { + background-color: var(--navbar-background-color-hover); +} + +.wy-side-nav-search > a:active, +.wy-side-nav-search .wy-dropdown > a:active { + background-color: var(--navbar-background-color-active); +} + +.wy-side-nav-search input[type=search] { + width: 100%; + border-radius: 50px; + padding: 6px 12px; + background-color: var(--input-background-color); + color: var(--body-color); + /* Avoid reflowing when toggling the focus state */ + border: 2px solid transparent; + box-shadow: none; + /* Make visual feedback instant */ + transition: none; + font-size: 14px; +} + +.wy-side-nav-search input[type="search"]:focus { + border: 2px solid var(--input-focus-border-color); +} + +.wy-side-nav-search input[type="search"]::placeholder { + color: var(--body-color); + opacity: 0.55; +} + +/* Navigation bar */ + +.wy-nav-side { + background-color: var(--navbar-background-color); +} + +.wy-menu-vertical header, +.wy-menu-vertical p.caption { + color: var(--navbar-heading-color); + + /* Improves the appearance of uppercase text */ + letter-spacing: 0.75px; +} + +/* Mobile navigation */ + +.wy-nav-top, +.wy-nav-top a { + background-color: var(--navbar-background-color); + color: var(--navbar-level-1-color); +} + +/* Version branch label below the logo */ +.wy-side-nav-search > div.version { + color: var(--navbar-level-3-color); + opacity: 0.9; +} + +/* First level of navigation items */ + +.wy-menu-vertical a { + color: var(--navbar-level-1-color); +} + +.wy-menu-vertical a:hover { + background-color: var(--navbar-background-color-hover); + color: var(--navbar-level-1-color); +} + +.wy-menu-vertical a:active { + background-color: var(--navbar-background-color-active); +} + +.wy-menu-vertical li.toctree-l1.current > a { + border: none; +} + +.wy-menu-vertical a button.toctree-expand, +.wy-menu-vertical li.toctree-l2 a button.toctree-expand { + color: var(--navbar-level-3-color); + opacity: 0.9; + margin-right: 6px; +} + +.wy-menu-vertical a:hover button.toctree-expand, +.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand { + color: var(--navbar-level-2-color); + opacity: 1; +} + +.wy-menu-vertical a:active button.toctree-expand, +.wy-menu-vertical li.toctree-l2 a:active button.toctree-expand { + color: var(--navbar-level-1-color); + opacity: 1; +} + +/* Second (and higher) levels of navigation items */ + +.wy-menu-vertical li.current a { + /* Make long words always display on a single line, keep wrapping for multiple words */ + /* This fixes the class reference titles' display with very long class names */ + display: flex; +} + +.wy-menu-vertical li.current a, +.wy-menu-vertical li.toctree-l2.current > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a { + background-color: var(--navbar-current-background-color); + color: var(--navbar-level-2-color); + border-color: var(--navbar-current-background-color); +} + +.wy-menu-vertical li.current a:hover, +.wy-menu-vertical li.toctree-l2.current > a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover, +.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a:hover { + background-color: var(--navbar-current-background-color-hover); +} + +.wy-menu-vertical li.current a:active, +.wy-menu-vertical li.toctree-l2.current > a:active, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:active, +.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a:active { + background-color: var(--navbar-current-background-color-active); +} + +.wy-menu-vertical a { + /* This overrides 8px margin added in other multi-selector rules */ + margin-right: 0; +} + +/* Banner panel in sidebar */ +.wy-nav-side .ethical-rtd.fixed { + position: fixed; +} + +/* Version selector (only visible on Read the Docs) */ + +.rst-versions { + background-color: var(--navbar-current-background-color); +} + +.rst-versions a, +.rst-versions .rst-current-version, +.rst-versions .rst-current-version .fa, +.rst-versions .rst-other-versions dd a { + color: var(--navbar-level-1-color); +} + +.rst-versions .rst-other-versions small { + color: var(--navbar-level-3-color); +} + +.rst-versions .rst-other-versions dd a:hover { + text-decoration: underline; +} + +.rst-versions .rst-other-versions { + color: var(--navbar-heading-color); +} + +.rst-versions .rst-current-version { + background-color: var(--navbar-current-background-color); +} + +.rst-versions .rst-current-version:hover { + background-color: var(--navbar-current-background-color-hover); +} + +.rst-versions .rst-current-version:active { + background-color: var(--navbar-current-background-color-active); +} + +.rst-versions.shift-up { + overflow-y: auto; +} + +/* Hide the obnoxious automatic highlight in search results */ +.rst-content .highlighted { + background-color: transparent; + font-weight: inherit; + padding: 0; +} + +/* Allows the scrollbar to be shown in the sidebar */ +@media only screen and (min-width: 769px) { + .wy-side-scroll { + overflow: hidden; + } + + .wy-nav-side .wy-side-scroll .ethical-rtd { + width: calc(300px - 1.25em); + padding: 0 0 0 1em; + } +} +.wy-menu.wy-menu-vertical { + overflow-y: auto; + overflow-x: hidden; + max-height: calc(100% - 243px); +} +@media screen and (max-width: 768px) { + .wy-nav-side { + padding-bottom: 44px; + } + .wy-menu.wy-menu-vertical { + overflow-y: initial; + max-height: initial; + } + .wy-nav-content { + min-height: calc(100vh - 64px); + min-height: calc(100dvh - 64px); + } +} + +/* Scrollbar styling */ +.wy-menu.wy-menu-vertical { + scrollbar-color: var(--navbar-scrollbar-color) var(--navbar-scrollbar-background); +} +.wy-menu.wy-menu-vertical::-webkit-scrollbar { + width: .75rem; +} +.wy-menu.wy-menu-vertical::-webkit-scrollbar-track { + background-color: var(--navbar-scrollbar-background); +} +.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb { + background-color: var(--navbar-scrollbar-color); +} +/* Firefox does the dimming on hover automatically. We emulate it for Webkit-based browsers. */ +.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb:hover { + background-color: var(--navbar-scrollbar-hover-color); +} +.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb:active { + background-color: var(--navbar-scrollbar-active-color); +} + +/* Misc tweaks */ + +.rst-columns { + column-width: 18em; +} + +.rst-content div.figure, .rst-content figure { + text-align: center; +} + +.wy-alert.wy-alert-danger { + background-color: var(--admonition-danger-background-color); +} + + +dark-mode-toggle::part(fieldset) { + padding-inline: 0.75rem; + padding-block: 0; +} + +dark-mode-toggle::part(darkLabel), +dark-mode-toggle::part(lightLabel), +dark-mode-toggle::part(toggleLabel){ + font-size: unset; +} + +div.graphviz > object { + filter: var(--graphviz-filter); +} + +/* Home page grid display */ +.grid { + list-style-type: none !important; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin: 1rem auto; + max-width: calc((160px + 2rem) * 4); +} + +.grid-item { + list-style-type: none !important; + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: 150px; + text-align: center; + margin: 1rem; +} + +.grid-item a { + display: block; + width: 150px; + height: 150px; + padding: 20px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border-radius: 1rem; + background: linear-gradient(135deg, #0070c5 0%, #5c13a5 100%); + color: white; +} + +.grid-item h2 { + font-size: 1rem; +} + +.grid-item img { + margin-bottom: 1rem; + max-width: 75%; +} + +.grid-item a:hover { + text-decoration: none; +} + +.grid-item p { + font-size: 0.9rem; + margin-top: 0.5rem; + color: var(--body-color); + font-weight: 200; + margin-left: -0.9em; + margin-right: -0.9em; + line-height: 1.4rem; +} + +.grid-icon { + line-height: 1.5; + font-size: 3rem; + color: white; +} + +.lastupdated { + font-weight: 200; + font-size: 0.9rem; +} + +/* Make actual document take all vertical space available so that footer is always at the bottom */ + +.rst-content { + flex: 1; + display: flex; + flex-direction: column; + width: 100%; +} + +.document { + flex-grow: 1; +} + +/* Custom search box, including search engine selection */ + +.search-container { + position: relative; +} + +#search-se-settings-icon { + position: absolute; + color: var(--body-color); + right: 10px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + opacity: 0.8; +} + +#search-se-menu { + display: none; + position: absolute; + font-size: 11px; + background-color: var(--input-background-color); + color: var(--body-color); + right: 0px; + top: 36px; + border: solid 1px var(--body-color); + border-radius: 10px; + z-index: 1000; +} + +#search-se-menu ul { + list-style: none; + margin: 0; + padding: 2px; +} + +#search-se-menu ul li { + padding: 8px 12px; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + gap: 1em; +} + +#search-se-menu [role="menuitemradio"]:focus { + background-color: var(--navbar-current-background-color-hover); + color: var(--navbar-level-1-color); + border-radius: 10px; +} + +#search-se-menu ul li .fa-check { + display: none; + } + + #search-se-menu ul li.selected .fa-check { + display: inline; + } + +.doxygroup::after { + content: 'Doxygen'; + display: inline-block; + background-color: var(--admonition-note-title-background-color); + color: var(--admonition-note-title-color); + padding: 2px 8px; + border-radius: 12px; + margin-left: 8px; + font-size: 0.875em; + font-weight: bold; +} + +.code-sample-list li { + margin-bottom: 0.25em; +} +.code-sample-name { + font-weight: bold; + padding-right: 0.5em; +} + +.code-sample-description { + font-weight: 300; +} + +.code-sample-description::before { + content: '\F0A9'; /* arrow-circle-right */ + font-family: 'FontAwesome'; + padding-right: 0.5em; +} + +li>a.code-sample-link.reference.internal { + font-weight: 100; +} + +li>a.code-sample-link.reference.internal.current { + text-decoration: underline; +} diff --git a/doc/_static/css/dark.css b/doc/_static/css/dark.css new file mode 100644 index 00000000..bb1c20c0 --- /dev/null +++ b/doc/_static/css/dark.css @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community + * Copyright (c) 2021, Teslabs Engineering S.L. + * SPDX-License-Identifier: CC-BY-3.0 + * + * Dark theme colors + */ + +:root { + --body-color: rgba(255, 255, 255, 0.85); + --content-wrap-background-color: #202326; + --content-background-color: #2e3236; + /* Decrease the logo opacity when using the dark theme to be less distracting */ + --logo-opacity: 0.85; + --navbar-background-color: #25282b; + --navbar-background-color-hover: #333639; + --navbar-background-color-active: #111417; + --navbar-current-background-color: #333639; + --navbar-current-background-color-hover: #44474a; + --navbar-current-background-color-active: #222528; + --navbar-level-1-color: #ddd; + --navbar-level-2-color: #ccc; + --navbar-level-3-color: #bbb; + --navbar-heading-color: #af7fe4; + --navbar-scrollbar-color: #af7fe4; + --navbar-scrollbar-hover-color: #9454db; + --navbar-scrollbar-active-color: #7929d2; + --navbar-scrollbar-background: #1c1e21; + + --link-color: #8cf; + --link-color-hover: #9df; + --link-color-active: #6ad; + --link-color-visited: #cb99f6; + --external-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEyIiB3aWR0aD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjOGNmIj48cGF0aCBkPSJtNy41IDcuMXYzLjRoLTZ2LTZoMy40Ii8+PHBhdGggZD0ibTUuNzY1IDFoNS4yMzV2NS4zOWwtMS41NzMgMS41NDctMS4zMS0xLjMxLTIuNzI0IDIuNzIzLTIuNjktMi42ODggMi44MS0yLjgwOC0xLjMxMy0xLjMxeiIvPjwvZz48L3N2Zz4K"); + --classref-badge-text-color: hsl(0, 0%, 70%); + + --hr-color: #555; + --table-row-odd-background-color: #3b3e41; + --code-background-color: #434649; + --code-border-color: #505356; + --code-literal-color: #faa; + --input-background-color: #333537; + --input-focus-border-color: #5f8cff; + + --search-input-background-color: #43464a; /* derived from --input-background-color */ + --search-match-color: #52b4ff; /* derived from --link-color */ + --search-match-background-color: #414c56; /* derived from --link-color */ + --search-active-color: #202326; + --search-credits-background-color: #202123; /* derived from --navbar-background-color */ + --search-credits-color: #6b6b6b; /* derived from --footer-color */ + --search-credits-link-color: #628fb1; /* derived from --link-color */ + + /* Colors taken from the Godot script editor with the Adaptive theme */ + --highlight-background-color: #202531; + --highlight-background-emph-color: #2d3444; + --highlight-default-color: rgba(255, 255, 255, 0.85); + --highlight-comment-color: rgba(204, 206, 211, 0.5); + --highlight-keyword-color: #ff7085; + --highlight-keyword2-color: #42ffc2; + --highlight-number-color: #a1ffe0; + --highlight-decorator-color: #abc8ff; + --highlight-type-color: #8effda; + --highlight-type2-color: #c6ffed; + --highlight-function-color: #57b3ff; + --highlight-operator-color: #abc8ff; + --highlight-string-color: #ffeca1; + + --admonition-note-background-color: #303d4f; + --admonition-note-color: #bfeeff; + --admonition-note-title-background-color: #305070; + --admonition-note-title-color: #bfefff; + --admonition-attention-background-color: #444033; + --admonition-attention-color: #ffeeaf; + --admonition-attention-title-background-color: #665022; + --admonition-attention-title-color: #ffeeaf; + --admonition-danger-background-color: #433; + --admonition-danger-color: #fcc; + --admonition-danger-title-background-color: #633; + --admonition-danger-title-color: #fcc; + --admonition-tip-background-color: #28382d; + --admonition-tip-color: #dfd; + --admonition-tip-title-background-color: #336648; + --admonition-tip-title-color: #dfd; + + --kbd-background-color: #595b5d; + --kbd-outline-color: #3d4144; + --kbd-shadow-color: #1e2023; + --kbd-text-color: #e2f2ff; + + --guiitems-background-color: #303d4f; + --guiitems-border-color: #7fbbe3; + + --btn-neutral-background-color: #404040; + --btn-neutral-hover-background-color: #505050; + --footer-color: #aaa; + + --graphviz-filter: invert(0.9) brightness(1.2); +} diff --git a/doc/_static/css/gcs.css b/doc/_static/css/gcs.css new file mode 100644 index 00000000..16501108 --- /dev/null +++ b/doc/_static/css/gcs.css @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2023, Benjamin Cabé . + * SPDX-License-Identifier: Apache-2.0 + * + * Custom stylesheet for Google Programmable Search Engine results. + */ + +.gs-webResult .gs-snippet, +.gs-fileFormatType, +.gs-spelling, +.gsc-refinementHeader, +.gsc-result-info, +.gsc-orderby-label { + color: var(--body-color) !important; +} + +.gsc-control-cse { + width: 100%; + padding: 0 !important; + font-family: inherit !important; + font-size: inherit !important; + background-color: inherit !important; + border: none !important; + font-size: inherit !important; +} + +.gsc-completion-container { + font-family: inherit !important; +} + +.gs-result .gs-title, .gs-result .gs-title * { + color: var(--link-color) !important; + background-color: var(--content-background-color) !important; +} + +.gs-result .gs-title:visited, .gs-result .gs-title:visited * { + color: var(--link-color-visited) !important; +} + +.gsc-results .gsc-cursor-box .gsc-cursor-page, +.gsc-results .gsc-cursor-box .gsc-cursor-current-page { + background-color: var(--content-background-color) !important; + color: var(--link-color) !important; +} + +.gs-result .gs-image, .gs-result .gs-promotion-image { + border: none !important; + padding-right: .5em; +} + +.gsc-table-result { + font-family: inherit !important; + padding-top: .5em !important; + font-size: inherit !important; +} + +.gsc-tabHeader.gsc-tabhActive, .gsc-refinementHeader.gsc-refinementhActive, +.gsc-tabHeader.gsc-tabhInactive, .gsc-refinementHeader.gsc-refinementhInactive { + background-color: inherit !important; +} + +.gs-no-results-result .gs-snippet, .gs-error-result .gs-snippet { + color: var(--admonition-attention-title-color) !important; + background-color: var(--admonition-attention-title-background-color) !important; +} + +.gsc-webResult .gsc-result { + background-color: inherit !important; + margin: 0; + padding: .5em 0; + border: none !important; + border-bottom: 1px solid var(--hr-color) !important; +} + +.gs-webResult div.gs-per-result-labels { + margin-top: 1.3em; + margin-bottom: 0.3em; + font-size:0.8em; +} + +.gs-webResult div.gs-per-result-labels span { + display: none; +} + +.gs-webResult div.gs-per-result-labels a.gs-label { + text-decoration: none !important; + cursor: pointer; + padding: 0.4em 0.6em; + margin-left: .5em; + color: var(--admonition-tip-title-color) !important; + background-color: var(--admonition-tip-title-background-color) !important; + border-radius: 50px; +} + +.gcsc-find-more-on-google { + color: var(--link-color) !important; +} + +.gcsc-find-more-on-google-magnifier { + fill: var(--link-color) !important; +} diff --git a/doc/_static/css/light.css b/doc/_static/css/light.css new file mode 100644 index 00000000..eb019863 --- /dev/null +++ b/doc/_static/css/light.css @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community + * Copyright (c) 2021, Teslabs Engineering S.L. + * SPDX-License-Identifier: CC-BY-3.0 + * + * Light theme colors + */ + +:root { + --body-color: #404040; + --content-wrap-background-color: #efefef; + --content-background-color: #fcfcfc; + --logo-opacity: 1.0; + --navbar-background-color: #333f67; + --navbar-background-color-hover: #29355c; + --navbar-background-color-active: #212d51; + --navbar-current-background-color: #212d51; + --navbar-current-background-color-hover: #182343; + --navbar-current-background-color-active: #131e3b; + --navbar-level-1-color: #c3e3ff; + --navbar-level-2-color: #b8d6f0; + --navbar-level-3-color: #a3c4e1; + --navbar-heading-color: #af7fe4; + --navbar-scrollbar-color: #af7fe4; + --navbar-scrollbar-hover-color: #9454db; + --navbar-scrollbar-active-color: #7929d2; + --navbar-scrollbar-background: #131e2b; + + --link-color: #237ab3; + --link-color-hover: #3091d1; + --link-color-active: #105078; + --link-color-visited: #9b59b6; + --external-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEyIiB3aWR0aD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMjk4MGI5Ij48cGF0aCBkPSJtNy41IDcuMXYzLjRoLTZ2LTZoMy40Ii8+PHBhdGggZD0ibTUuNzY1IDFoNS4yMzV2NS4zOWwtMS41NzMgMS41NDctMS4zMS0xLjMxLTIuNzI0IDIuNzIzLTIuNjktMi42ODggMi44MS0yLjgwOC0xLjMxMy0xLjMxeiIvPjwvZz48L3N2Zz4K"); + --classref-badge-text-color: hsl(0, 0%, 45%); + + --hr-color: #e1e4e5; + --table-row-odd-background-color: #f3f6f6; + --code-background-color: #fff; + --code-border-color: #e1e4e5; + --code-literal-color: #d04c60; + --input-background-color: #fcfcfc; + --input-focus-border-color: #5f8cff; + + --search-input-background-color: #e6eef3; /* derived from --input-background-color */ + --search-match-color: #2c6b96; /* derived from --link-color */ + --search-match-background-color: #e3f2fd; /* derived from --link-color */ + --search-active-color: #efefef; + --search-credits-background-color: #333f67; /* derived from --navbar-background-color */ + --search-credits-color: #b3b3b3; /* derived from --footer-color */ + --search-credits-link-color: #4392c5; /* derived from --link-color */ + + --highlight-background-color: #f0f2f4; + --highlight-background-emph-color: #dbe6c3; + --highlight-default-color: #404040; + --highlight-comment-color: #408090; + --highlight-keyword-color: #007020; + --highlight-keyword2-color: #902000; + --highlight-number-color: #208050; + --highlight-decorator-color: #4070a0; + --highlight-type-color: #007020; + --highlight-type2-color: #0e84b5; + --highlight-function-color: #06287e; + --highlight-operator-color: #666666; + --highlight-string-color: #4070a0; + + --admonition-note-background-color: #e7f2fa; + --admonition-note-color: #404040; + --admonition-note-title-background-color: #6ab0de; + --admonition-note-title-color: #fff; + --admonition-attention-background-color: #ffedcc; + --admonition-attention-color: #404040; + --admonition-attention-title-background-color: #f0b37e; + --admonition-attention-title-color: #fff; + --admonition-danger-background-color: #fcf3f2; + --admonition-danger-color: #404040; + --admonition-danger-title-background-color: #e9a499; + --admonition-danger-title-color: #fff; + --admonition-tip-background-color: #dbfaf4; + --admonition-tip-color: #404040; + --admonition-tip-title-background-color: #1abc9c; + --admonition-tip-title-color: #fff; + + --kbd-background-color: #fafbfc; + --kbd-outline-color: #d1d5da; + --kbd-shadow-color: #b0b7bf; + --kbd-text-color: #444d56; + + --guiitems-background-color: #e7f2fa; + --guiitems-border-color: #7fbbe3; + + --btn-neutral-background-color: #f3f6f6; + --btn-neutral-hover-background-color: #e5ebeb; + --footer-color: #747474; + + --graphviz-filter: none; +} diff --git a/doc/_static/images/logo.png b/doc/_static/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..861db7d9f97b1d5f347b8abc193620c3c03cd9c0 GIT binary patch literal 73757 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 B^G5&x literal 0 HcmV?d00001 diff --git a/doc/_static/images/west-mr-model.png b/doc/_static/images/west-mr-model.png new file mode 100644 index 0000000000000000000000000000000000000000..ddbfdb62a6fcd398e4e25dcfd92ab8edb56f39b1 GIT binary patch literal 67684 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 yhp;QBW|^Mvv;)s{G{!KUtsM*FG`V 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 + * SPDX-License-Identifier: CC-BY-3.0 + */ + + +// Handle page scroll and adjust sidebar accordingly. + +// Each page has two scrolls: the main scroll, which is moving the content of the page; +// and the sidebar scroll, which is moving the navigation in the sidebar. +// We want the logo to gradually disappear as the main content is scrolled, giving +// more room to the navigation on the left. This means adjusting the height +// available to the navigation on the fly. +const registerOnScrollEvent = (function(){ + // Configuration. + + // The number of pixels the user must scroll by before the logo is completely hidden. + const scrollTopPixels = 137; + // The target margin to be applied to the navigation bar when the logo is hidden. + const menuTopMargin = 54; + // The max-height offset when the logo is completely visible. + const menuHeightOffset_default = 210; + // The max-height offset when the logo is completely hidden. + const menuHeightOffset_fixed = 63; + // The distance between the two max-height offset values above; used for intermediate values. + const menuHeightOffset_diff = (menuHeightOffset_default - menuHeightOffset_fixed); + + // Media query handler. + return function(mediaQuery) { + // We only apply this logic to the "desktop" resolution (defined by a media query at the bottom). + // This handler is executed when the result of the query evaluation changes, which means that + // the page has moved between "desktop" and "mobile" states. + + // When entering the "desktop" state, we register scroll events and adjust elements on the page. + // When entering the "mobile" state, we clean up any registered events and restore elements on the page + // to their initial state. + + const $window = $(window); + const $sidebar = $('.wy-side-scroll'); + const $search = $sidebar.children('.wy-side-nav-search'); + const $menu = $sidebar.children('.wy-menu-vertical'); + + if (mediaQuery.matches) { + // Entering the "desktop" state. + + // The main scroll event handler. + // Executed as the page is scrolled and once immediately as the page enters this state. + const handleMainScroll = (currentScroll) => { + if (currentScroll >= scrollTopPixels) { + // After the page is scrolled below the threshold, we fix everything in place. + $search.css('margin-top', `-${scrollTopPixels}px`); + $menu.css('margin-top', `${menuTopMargin}px`); + $menu.css('max-height', `calc(100% - ${menuHeightOffset_fixed}px)`); + } + else { + // Between the top of the page and the threshold we calculate intermediate values + // to guarantee a smooth transition. + $search.css('margin-top', `-${currentScroll}px`); + $menu.css('margin-top', `${menuTopMargin + (scrollTopPixels - currentScroll)}px`); + + if (currentScroll > 0) { + const scrolledPercent = (scrollTopPixels - currentScroll) / scrollTopPixels; + const offsetValue = menuHeightOffset_fixed + menuHeightOffset_diff * scrolledPercent; + $menu.css('max-height', `calc(100% - ${offsetValue}px)`); + } else { + $menu.css('max-height', `calc(100% - ${menuHeightOffset_default}px)`); + } + } + }; + + // The sidebar scroll event handler. + // Executed as the sidebar is scrolled as well as after the main scroll. This is needed + // because the main scroll can affect the scrollable area of the sidebar. + const handleSidebarScroll = () => { + const menuElement = $menu.get(0); + const menuScrollTop = $menu.scrollTop(); + const menuScrollBottom = menuElement.scrollHeight - (menuScrollTop + menuElement.offsetHeight); + + // As the navigation is scrolled we add a shadow to the top bar hanging over it. + if (menuScrollTop > 0) { + $search.addClass('fixed-and-scrolled'); + } else { + $search.removeClass('fixed-and-scrolled'); + } + }; + + $search.addClass('fixed'); + + $window.scroll(function() { + handleMainScroll(window.scrollY); + handleSidebarScroll(); + }); + + $menu.scroll(function() { + handleSidebarScroll(); + }); + + handleMainScroll(window.scrollY); + handleSidebarScroll(); + } else { + // Entering the "mobile" state. + + $window.unbind('scroll'); + $menu.unbind('scroll'); + + $search.removeClass('fixed'); + + $search.css('margin-top', `0px`); + $menu.css('margin-top', `0px`); + $menu.css('max-height', 'initial'); + } + }; + })(); + + $(document).ready(() => { + // Initialize handlers for page scrolling and our custom sidebar. + const mediaQuery = window.matchMedia('only screen and (min-width: 769px)'); + + registerOnScrollEvent(mediaQuery); + mediaQuery.addListener(registerOnScrollEvent); + }); diff --git a/doc/_static/js/dark-mode-toggle-stylesheets-loader.min.js b/doc/_static/js/dark-mode-toggle-stylesheets-loader.min.js new file mode 100644 index 00000000..4b708b54 --- /dev/null +++ b/doc/_static/js/dark-mode-toggle-stylesheets-loader.min.js @@ -0,0 +1,2 @@ +// @license © 2024 Google LLC. Licensed under the Apache License, Version 2.0. +(()=>{const e="dark-mode-toggle-stylesheets";const s="dark-mode-toggle";const t="light";const l="dark";let o=document.getElementById(e).textContent;let c=null;try{c=localStorage.getItem(s)}catch(e){}const a=/\(\s*prefers-color-scheme\s*:\s*light\s*\)/gi;const r=/\(\s*prefers-color-scheme\s*:\s*dark\s*\)/gi;switch(c){case t:o=o.replace(a,"$&, all").replace(r,"$& and not all");break;case l:o=o.replace(r,"$&, all").replace(a,"$& and not all");break}document.write(o)})(); \ No newline at end of file diff --git a/doc/_static/js/dark-mode-toggle.min.mjs b/doc/_static/js/dark-mode-toggle.min.mjs new file mode 100644 index 00000000..9c78635c --- /dev/null +++ b/doc/_static/js/dark-mode-toggle.min.mjs @@ -0,0 +1,2 @@ +// @license © 2019 Google LLC. Licensed under the Apache License, Version 2.0. +const e=document;let t={};try{t=localStorage}catch(e){}const i="prefers-color-scheme";const a="media";const s="light";const r="dark";const h="system";const o=`(${i}:${r})`;const l=`(${i}:${s})`;const n="link[rel=stylesheet]";const c="remember";const d="legend";const p="toggle";const b="switch";const g="three-way";const m="appearance";const u="permanent";const f="mode";const k="colorschemechange";const y="permanentcolorscheme";const v="all";const $="not all";const L="dark-mode-toggle";const T="https://googlechromelabs.github.io/dark-mode-toggle/demo/";const W=(e,t,i=t)=>{Object.defineProperty(e,i,{enumerable:true,get(){const e=this.getAttribute(t);return e===null?"":e},set(e){this.setAttribute(t,e)}})};const w=(e,t,i=t)=>{Object.defineProperty(e,i,{enumerable:true,get(){return this.hasAttribute(t)},set(e){if(e){this.setAttribute(t,"")}else{this.removeAttribute(t)}}})};const x=e.createElement("template");x.innerHTML=`

`;export class DarkModeToggle extends HTMLElement{static get observedAttributes(){return[f,m,u,d,s,r,c]}constructor(){super();W(this,f);W(this,m);W(this,d);W(this,s);W(this,r);W(this,h);W(this,c);w(this,u);this.t=null;this.i=null;e.addEventListener(k,(e=>{this.mode=e.detail.colorScheme;this.h();this.o();this.l()}));e.addEventListener(y,(e=>{this.permanent=e.detail.permanent;this.p.checked=this.permanent;this.l()}));this.m()}m(){const t=this.attachShadow({mode:"open"});t.append(x.content.cloneNode(true));this.t=e.querySelectorAll(`${n}[${a}*=${i}][${a}*="${r}"]`);this.i=e.querySelectorAll(`${n}[${a}*=${i}][${a}*="${s}"]`);this.u=t.querySelector("[part=lightRadio]");this.k=t.querySelector("[part=lightLabel]");this.v=t.querySelector("[part=darkRadio]");this.$=t.querySelector("[part=darkLabel]");this.L=t.querySelector("[part=toggleCheckbox]");this.T=t.querySelector("[part=toggleLabel]");this.W=t.querySelector("[part=lightThreeWayRadio]");this.R=t.querySelector("[part=lightThreeWayLabel]");this.C=t.querySelector("[part=systemThreeWayRadio]");this.M=t.querySelector("[part=systemThreeWayLabel]");this.S=t.querySelector("[part=darkThreeWayRadio]");this._=t.querySelector("[part=darkThreeWayLabel]");this.A=t.querySelector("legend");this.D=t.querySelector("aside");this.p=t.querySelector("[part=permanentCheckbox]");this.O=t.querySelector("[part=permanentLabel]")}connectedCallback(){const e=matchMedia(o).media!==$;if(e){matchMedia(o).addListener((({matches:e})=>{if(this.permanent){return}this.mode=e?r:s;this.j(k,{colorScheme:this.mode})}))}let i=false;try{i=t.getItem(L)}catch(e){}if(i&&[r,s].includes(i)){this.mode=i;this.p.checked=true;this.permanent=true}else if(e){this.mode=matchMedia(l).matches?s:r}if(!this.mode){this.mode=s}if(this.permanent&&!i){try{t.setItem(L,this.mode)}catch(e){}}if(!this.appearance){this.appearance=p}this.P();this.h();this.o();this.l();[this.u,this.v].forEach((e=>{e.addEventListener("change",(()=>{this.mode=this.u.checked?s:r;this.o();this.l();this.j(k,{colorScheme:this.mode})}))}));this.L.addEventListener("change",(()=>{this.mode=this.L.checked?r:s;this.h();this.l();this.j(k,{colorScheme:this.mode})}));this.W.addEventListener("change",(()=>{this.mode=s;this.permanent=true;this.o();this.h();this.l();this.j(k,{colorScheme:this.mode});this.j(y,{permanent:this.permanent})}));this.S.addEventListener("change",(()=>{this.mode=r;this.permanent=true;this.o();this.h();this.l();this.j(k,{colorScheme:this.mode});this.j(y,{permanent:this.permanent})}));this.C.addEventListener("change",(()=>{this.mode=this.H();this.permanent=false;this.o();this.h();this.l();this.j(k,{colorScheme:this.mode});this.j(y,{permanent:this.permanent})}));this.p.addEventListener("change",(()=>{this.permanent=this.p.checked;this.l();this.j(y,{permanent:this.permanent})}));this.q();this.j(k,{colorScheme:this.mode});this.j(y,{permanent:this.permanent})}attributeChangedCallback(e,i,a){if(e===f){const e=[s,h,r];if(!e.includes(a)){throw new RangeError(`Allowed values are: "${e.join(`", "`)}".`)}if(matchMedia("(hover:none)").matches&&this.remember){this.B()}if(this.permanent){try{t.setItem(L,this.mode)}catch(e){}}this.h();this.o();this.l();this.q()}else if(e===m){const e=[p,b,g];if(!e.includes(a)){throw new RangeError(`Allowed values are: "${e.join(`", "`)}".`)}this.P()}else if(e===u){if(this.permanent){if(this.mode){try{t.setItem(L,this.mode)}catch(e){}}}else{try{t.removeItem(L)}catch(e){}}this.p.checked=this.permanent}else if(e===d){this.A.textContent=a}else if(e===c){this.O.textContent=a}else if(e===s){this.k.textContent=a;if(this.mode===s){this.T.textContent=a}}else if(e===r){this.$.textContent=a;if(this.mode===r){this.T.textContent=a}}}H(){return matchMedia(l).matches?s:r}j(e,t){this.dispatchEvent(new CustomEvent(e,{bubbles:true,composed:true,detail:t}))}P(){this.u.hidden=this.k.hidden=this.v.hidden=this.$.hidden=this.L.hidden=this.T.hidden=this.W.hidden=this.R.hidden=this.C.hidden=this.M.hidden=this.S.hidden=this._.hidden=true;switch(this.appearance){case b:this.u.hidden=this.k.hidden=this.v.hidden=this.$.hidden=false;break;case g:this.W.hidden=this.R.hidden=this.C.hidden=this.M.hidden=this.S.hidden=this._.hidden=false;break;case p:default:this.L.hidden=this.T.hidden=false;break}}h(){if(this.mode===s){this.u.checked=true}else{this.v.checked=true}}o(){if(this.mode===s){this.T.style.setProperty(`--${L}-checkbox-icon`,`var(--${L}-light-icon,url("${T}moon.png"))`);this.T.textContent=this.light;if(!this.light){this.T.ariaLabel=r}this.L.checked=false}else{this.T.style.setProperty(`--${L}-checkbox-icon`,`var(--${L}-dark-icon,url("${T}sun.png"))`);this.T.textContent=this.dark;if(!this.dark){this.T.ariaLabel=s}this.L.checked=true}}l(){this.R.ariaLabel=s;this.M.ariaLabel=h;this.R.ariaLabel=r;this.R.textContent=this.light;this.M.textContent=this.system;this._.textContent=this.dark;if(this.permanent){if(this.mode===s){this.W.checked=true}else{this.S.checked=true}}else{this.C.checked=true}}q(){if(this.mode===s){this.i.forEach((e=>{e.media=v;e.disabled=false}));this.t.forEach((e=>{e.media=$;e.disabled=true}))}else{this.t.forEach((e=>{e.media=v;e.disabled=false}));this.i.forEach((e=>{e.media=$;e.disabled=true}))}}B(){this.D.style.visibility="visible";setTimeout((()=>{this.D.style.visibility="hidden"}),3e3)}}customElements.define(L,DarkModeToggle); \ No newline at end of file diff --git a/doc/_templates/breadcrumbs.html b/doc/_templates/breadcrumbs.html new file mode 100644 index 00000000..3852afcf --- /dev/null +++ b/doc/_templates/breadcrumbs.html @@ -0,0 +1,34 @@ +{% extends "!breadcrumbs.html" %} +{% block breadcrumbs %} + + {# parameterize default name "Docs" in breadcrumb via docs_title in conf.py #} + {% if not docs_title %} + {% set docs_title = "Docs" %} + {% endif %} + +
  • {{ docs_title }} »
  • + {% for doc in parents %} +
  • {{ doc.title }} »
  • + {% endfor %} +
  • {{ title }}
  • + +{% endblock %} +{%- block breadcrumbs_aside %} +
  • + +
  • +
  • + {%- if display_gh_links %} + {% set gh_blob_url = pagename | gh_link_get_blob_url %} + {% if gh_blob_url %} + {{ _('Open on GitHub') }} + {% endif %} + {%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %} + {%- if sha1 %} + + {{ _('Report an issue with this page')}} + + {% endif %} + {% endif %} +
  • +{%- endblock %} diff --git a/doc/_templates/footer.html b/doc/_templates/footer.html new file mode 100644 index 00000000..9dacea71 --- /dev/null +++ b/doc/_templates/footer.html @@ -0,0 +1,18 @@ +{% extends "!footer.html" %} +{% block contentinfo %} +

    + {%- if show_copyright %} + © Copyright {{ copyright }}. + {%- endif %} + + {%- if last_updated %} +

    + Last generated: {{ last_updated }}. + {%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %} + {%- if git_last_updated %} + Last source update: {{ git_last_updated }}. + {%- endif %} +
    + {%- endif -%} +

    +{% endblock %} diff --git a/doc/_templates/gsearch.html b/doc/_templates/gsearch.html new file mode 100644 index 00000000..19534663 --- /dev/null +++ b/doc/_templates/gsearch.html @@ -0,0 +1,17 @@ +{%- extends "!search.html" %} + +{%- block scripts %} + {{ super.super() }} + +{%- endblock %} + +{% block footer %} + {{ super.super() }} +{% endblock %} + +{% block body %} +

    {{ _('Search Results') }}

    + +
    +{% endblock %} diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html new file mode 100644 index 00000000..699c8ee9 --- /dev/null +++ b/doc/_templates/layout.html @@ -0,0 +1,41 @@ +{% extends "!layout.html" %} +{% block document %} + {% if is_release %} +
    + The latest development version + of this page may be more current than this released {{ version }} version. +
    + {% endif %} + {{ super() }} +{% endblock %} +{% block menu %} +
    + {% include "zversions.html" %} + {{ super() }} + {% if reference_links %} +
    +

    Reference

    +
      + {% for title, url in reference_links.items() %} +
    • + {{ title }} +
    • + {% endfor %} +
    +
    + {% endif %} +
    +{% endblock %} +{% block extrahead %} + + {# Use dark mode loader script to prevent "flashing" of the page on load. + As we need a