Commit Graph

119 Commits

Author SHA1 Message Date
Martí Bolívar a58261fc39 tree-wide: move CLI into new west.app package
This relates to issue #38, the TL;DR of which is that we've never
gotten around to properly separating west's application internals from
its API in source code, and instead relied on documentation to spell
out exactly what the API was that users could rely on.

Let's start fixing that by moving everything users can't rely on into
a new west.app. This includes everything in west.commands except the
__init__ module, so we can just make that a new src/west/commands.py
file and have it be a module instead of a package. This lets its
pykwalify schema file, west-commands-schema.yml, sit next to it in
src/west, which is flatter than before.

The code changes in this commit (source lines changed, rather than
files just getting moved around) are:

- change the entry point in setup.py to west.app.main:main
- change some imports in src/west/app/main.py to import from
  west.app instead of west.commands
- add a new src/west/app/__init__.py, since we're not using
  namespace packages
- changes in MANIFEST.in and test_help.py to reflect new paths
- adjust some comments and docstrings

This change makes the API divide clearer. This in turn exposes some
problems with our use of west.log from west.manifest:

1. logging to stdout is a bad practice from a library
2. west.log also uses global state (which relates to #149 also)
   which non-command-line users won't have set up properly
   (this is an example of why #1 is true)

Subsequent commits will move to only using west.log from within
west.app.* and the existing deprecated west.build and west.cmake APIs,
which users should be migrating away from anyway.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-22 07:36:31 -05:00
Martí Bolívar be719a502e manifest: support maps of imports
This completes the feature set for west manifest imports. We include a
test of name whitelists from the documentation as a basic sanity
check. Further testing is left to future work.

To close out this feature after this, we should only need more error
handling and testing. In particular, beyond general coverage issues,
we need to try to reject any obvious import cycles, and add tests for
the same.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-20 14:01:57 +01:00
Martí Bolívar 11b4606a0b tests: improve west.manifest coverage
Add additional line coverage for manifest.py using output from pycov.

I'm pretty happy with the resulting level of statement coverage (94%)
and the number of bugs that got shaken out by writing these (5 real
ones along with a couple of other improvements).

The remaining 6% is mostly trivial or part of the unimplemented
functions needed to import maps. The trivial stuff can get addressed
some other day if we're interested in getting to 100%, but I think
it's time to move on to implementing map imports after this, now that
we've got better test coverage for the manifest API in general and its
basic import feature in particular.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar b3954d0728 tests: add regression tests for west init failures
Improve test coverage for when west init ought to die with an error
because it's being asked to re-bootstrap something that's already
initialized.

- bootstrap init must not initialize a subdirectory that's already
- subprocess failure is not enough: we need to see 'already
  initialized' in the error output, or it could be some other failure

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar e8fafed5cd tree-wide: add python file copyright headers
And update a couple.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 17:14:36 +01:00
Martí Bolívar 28e35f0705 tree-wide: rename "installation" to "workspace"
The term "west installation" is inaccurate since 0.6, since we no longer
clone west into .west/west.

The term "workspace" is more familiar and seems to be more readily
understood, so switch to that instead. Keep backwards compatibility
with the requires_installation kwarg and attribute to WestCommand for
now.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 09:44:36 +01:00
Martí Bolívar 47b5f710e0 tree-wide: use f-strings more, tweak logs
Use f-strings instead of str.format() or string concatenation with +
whenever practical. Tweak a few log messages while we're here.

I may be getting a little f-string-happy, but I think having a single,
consistent style throughout the code base makes things easier to read,
and f-strings look like the natural default choice to me.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-16 09:18:30 -08:00
Martí Bolívar 6bb4247e12 tests: add regression tests for tag revisions
Add a remote repository to the setup we create in conftest.py whose
revision is a tag. Add testing for it in project.py, generalizing
update_helper() a bit while doing this to keep the code readable.

This adds coverage for basic west operations when manifest projects
have revisions which are tags.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-14 09:46:07 -08:00
Martí Bolívar fa9db58c42 manifest: add infrastructure for "simple" imports
Add the API-level features required to implement manifest imports of
simple files, directories, and sequences of these.

Defer implementation of maps as import keys and import loop detection
for now. There's already quite a bit to test here. We'll add the rest
in follow-up commits, once we've fleshed out the built-in commands.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-12-20 16:36:05 -08:00
Martí Bolívar 885828ebc0 main.py: re-work, adding a new WestApp class
The main() function has gotten really long, and it's getting hard to
read. I want to break it up, but there's a fair bit of interdependent
state to manage.

Rather than using global variables, create a WestApp instance to
contain them all and use it instead. This helps with readability
without making #149 harder to do.

We'll extend this later to handle manifest imports.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-12-04 12:33:07 +01:00
Martí Bolívar 630f069f7f manifest: delete Remote and Defaults API
Let's just get rid of this entirely to make it super clear that those
sections only have a meaning within the parsing of a single manifest
file, and are not relevant to the abstract representation of a
manifest.

This lets us rewrite the Project() constructor so it matches the tuple
representation in the manifest imports documentation quite closely.
This should hopefully make the API easier to use and understand.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-12-04 12:33:07 +01:00
Martí Bolívar 0d1dfa523f tests: fixes for windows
The code being tested is fine; there are just issues in the test cases
which make them fail on Windows.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-11-18 11:17:57 +01:00
Martí Bolívar ae784d516d tests: adjust for windows incompatibilities
Windows does a few things differently. Deal with it.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-11-18 11:17:57 +01:00
Martí Bolívar 564e1d4659 main: fix up help printing
We are getting an extra newline at the end of our help, which is
inconsistent with how argparse usually works and is causing tox issues
on Windows.

Avoid having an empty line at the end of help messages.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-11-18 11:17:57 +01:00
Martí Bolívar 159f16fc90 manifest: re-work Project API and as_dict() methods
Functional differences:

- Project and ManifestProject don't use __slots__ anymore
- you can no longer set ManifestProject.revision
- the Manifest remotes, defaults, get_remote() attributes/method are gone
- the Project remote attribute is gone
- frozen dictionaries have inlined URLs now, not remotes/defaults

These breaking changes are going to be needed for manifest importing.
We can't keep exposing defaults and remotes objects anymore, because
the semantics for project overrides mean that they aren't sensible
concepts at the API level.

Also save enough state in Project and ManifestProject to find out when
an attribute's data was explicitly part of the manifest file, or came
from a default. This will be useful when applying project overrides.

Update test_project.py and test_manifest.py to keep up with these
changes.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-11-11 18:28:20 +01:00
Marti Bolivar 26ee313d78 manifest: change how versioning works
Upon review, we've decided to version the manifest files using a
separate-but-related namespace to west version numbers.

Summary of changes:

- If the manifest schema changes in west X.Y, that new manifest schema
  version is also X.Y. So if west 0.8 adds new manifest features not
  available in 0.7, west 0.8 supports manifest schema 0.8.

- If the manifest schema does *not* change in west X.(Y+1), the
  manifest schema is the same as it was in X.Y. So if west 0.9 has the
  same manifest schema as west 0.8, then west 0.9 still has manifest
  schema 0.8.

This change lets us pin a single manifest schema version to each set
of changes, without sacrificing our ability to say "you need at least
west X.Y to support this manifest".

Suggested-by: Carles Cufí <carles.cufi@nordicsemi.no>
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-10-21 10:21:01 +02:00
Marti Bolivar e2325ca348 main: reorganize some internals
This refactoring will make it easier to handle ManifestVersionError.

Make 'west help' invoke a WestCommand too. API improvements made over
time make this easy to do.

It also has the pleasant side effect of making it really easy for
"west --help init" to be equivalent to "west help init" instead of
"west --help".

It works slightly different in case of error, though
("west --help unknown" produces different output than "west help
unknown"). I can't fix that without breaking the argparse abstraction
barrier, though, so it's OK.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-10-15 14:16:40 +02:00
Marti Bolivar 18857356bd manifest: support minimum required west version
As we evolve the manifest data, we want to be able to enforce a
minimum version of west required to parse it. Add an optional
'version' key to the data to make this possible.

We have to validate this before checking the manifest against the
schema, as later versions of west will likely extend the schema in
ways that would raise errors if we used our schema to check the data.

We allow the version to be parsed as a YAML float (like 1.0) and
convert it to a string as a convenience for the user.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-10-15 14:16:40 +02:00
Marti Bolivar 428ef11b38 manifest: accept strings as Manifest.from_data args
It's convenient when using this API to be able to pass a string
containing YAML data instead of requiring the caller to load the YAML
data every time.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-10-15 14:16:40 +02:00
Marti Bolivar 44faeaa3de commands: fix project clone with --clone-depth
Add a mandatory space between shell arguments. Fix the test cases so
they actually test this as advertised.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-10-02 09:10:28 -06:00
Marti Bolivar 88d750bed5 main: tweak 'west help' text for extensions
Use the phrase "extension commands" and print the project path along
with its name.

We don't use {name_and_path} here because users probably aren't used
to that format yet.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-09-26 13:57:52 -06:00
Marti Bolivar a335ea0510 commands: add 'west topdir' command
This just prints the top level directory of the west installation.

To fit it into the 'west help' output, tweak the section headings.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-09-26 13:57:52 -06:00
Marti Bolivar dc031a6385 main: fix west help <some-extension-command>
This slipped through the cracks when adding the manifest field to each
command instance in 7694f88 ("commands: save the parsed manifest from
main"). It only shows up for extensions -- built-ins work fine.

Add a regression test.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-09-06 12:39:52 -06:00
Marti Bolivar f511662b4c tests: tweak extension command in conftest
Adjust the name of the extension command provided in the test
environment, along with some related identifiers, so they're easier to
grep for. Make the help in the yaml file consistent with the python file.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-09-06 12:39:52 -06:00
Marti Bolivar f170447619 tests: test_help cosmetics
Adjust some comments and remove parentheses (which are unnecessary in
assert statements in Python).

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-09-06 12:39:52 -06:00
Marti Bolivar ecb81be96b tests: fix test_help
There is a return that got in there that makes the test inoperative.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-09-06 12:39:52 -06:00
Marti Bolivar 060bd29c45 manifest: correct several design and implementation issues
The west.manifest module is not in great shape:

- Though it's possible to create a manifest from data, this still
  looks for a topdir and a manifest.path configuration option on
  disk. This is wrong and contrary to the goal that we can parse
  manifest data independently of the file system.

  You can see that this doesn't really make sense in the hacks that
  the west init implementation needs to make things work, and the fact
  that all the tests which operate on data only have to patch
  west_topdir(), etc.

- The Project definition repeatedly finds the west topdir. Even
  when this is necessary, it should only be done once, and the value
  cached and passed around.

- The ManifestProject abstraction makes several bizarre semantic
  decisions, some of which never made sense, some of which are
  just stale leftovers from when it was SpecialProject.

- The manifest_path() helper mutates the global configuration object

Add some new kwargs to the Manifest factories and constructor, which
allow the user to avoid using west_topdir() or west.configuration when
they do not want to, and propagate the new information down into
Project and ManifestProject.

This allows users to parse manifest files and data without forcing
them to be inside an actual installation (and/or to parse other
manifest files than the one currently pointed to by manifest.path), at
the cost of not having abspath or posixpath attributes in some cases.

Fix up Project by taking a new topdir kwarg and saving it in a slot.

Fix up ManifestProject so that it generally makes more sense. This now
enforces an existing requirement in the documentation that no project
can be named "manifest", as that's reserved for the manifest
repository. Fix some other thinkos as well by deprecating the revision
and url kwargs, which are SpecialProject leftovers, and taking the
path as an argument as-is, even though that means it can be None now.

I've tried to preserve backwards compatibility whenever possible,
especially in situations where the user just wants to parse the
manifest in the current west installation based on file system
searches and configuration options.

The additional kwargs to Project and ManifestProject are breaking
changes for any code which was using this module for something else,
but the lack of sense that those made before probably meant such
code didn't do anything useful, so that's okay.

This also breaks compatibility with "west list zephyr" when run
outside of the top level directory -- you need to say "west list
manifest" or give the complete relative path to zephyr now.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-08-30 17:32:57 -06:00
Marti Bolivar d7df27c370 configuration: allow callers to specify west topdir
Add a topdir argument to each of these functions:

- read_config()
- update_config()
- delete_config()

If set, then topdir/.west/config will be used as the local
configuration file if necessary. This allows users of this module to
decouple themselves from west.util.west_dir() without having to resort
to temporarily setting environment variables.

Keep the tests up to date, adding a couple of test cases to make sure
the new kwarg works as expected.

While we're here, re-work the fixture setup so we don't ever have to
monkey-patch west.configuration._location() by always pointing the
WEST_CONFIG_xxx environment variables inside the tmpdir we're running
each test case from. This lets us avoid some extra work in tox.ini and
makes the resulting test code easier to read, without sacrificing any
safety in terms of touching the user's actual files.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-08-30 17:32:57 -06:00
Marti Bolivar ed37d67c36 manifest: fix get_projects() for unknown projects
The control flow when there is an unknown project is wrong: this is
calling is_cloned() on None. Indent it properly and add a regression
test.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-08-19 23:47:20 +02:00
Marti Bolivar b9cd8db734 test_project.py: remove invalid tests
The diff and status commands with extra arguments never worked.
Remove the invalid test cases for them. The next patch is going to
fail this sort of invocation with an error instead of silently
ignoring it.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-08-17 15:59:42 +02:00
Marti Bolivar bfc6786636 manifest: allow 'repo-path' to specify the path within a remote
Users have provided negative feedback about some specifics related to
the new restriction that project names must be unique.

In particular, there is a use case for fetching the same project (the
LittleVGL graphics library) into two separate paths with two separate
revisions (to allow Kconfig to select between two major versions).

Since project names must now be unique, this would require the use of
the `url` attribute instead of `remote` (since the URL is of course
the same for both "projects", "remote.url-base + name" cannot be used
without violating name uniqueness).

To make it possible to keep using remotes, add a new optional
'repo-path' attribute to each project. If given, then 'remote.url-base
+ repo-path' forms the fetch URL.

Like remote itself, 'repo-path' cannot be combined with 'url'.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-07-26 11:33:01 +02:00
Marti Bolivar a4af95471a manifest: fix incorrect parsing with url + default remote
Manifests which use both default remotes and projects with URL
elements may incorrectly be rejected as invalid. Fix this and add a
regression test.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-07-26 11:33:01 +02:00
Marti Bolivar 4dd845d8d3 west list: compatibility-breaking improvements
- The default west list format string is not particularly readable
  most of the time. Tweak it so it's better.

- replace multi-word strings like "(not set)" with single word
  equivalents like "N/A", which are easier to deal with in pipelines
  to cut, awk, etc.

- add a new {sha} format specifier that always produces a 40-character
  SHA, or the string N/A padded to the correct length.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-06-07 11:37:48 +02:00
Marti Bolivar 0da14440c6 commands: config: add -d and -D options for deleting
These allow the user to delete existing options.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar 4fe9d4a042 configuration: add delete_config()
We currently have no way to delete options once set. This is not good
for users that want to delete things so they go back to their default
values. Add a library API and tests for this; we'll extend the config
command with options that use them next.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar 46ca8354bd conftest.py: add license/copyright header
This was missing.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar 6cf0a0236b configuration: allow environment overrides
Add three new environment variables which can be used to override the
configuration file locations: WEST_CONFIG_SYSTEM, WEST_CONFIG_GLOBAL,
and WEST_CONFIG_LOCAL.

Use them in the tests. This also has the beneficial side effect of
making sure that "real" system settings do not interfere with the test
environment.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar b94b71bbfa tests: allow cmd() to use non-standard environment
We'll use this the next patch. It's useful for isolation, because the
environment is one of the things that does live on between tests.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar 06683b791c commands: config: add --list option
This prints all existing config options and their values.
It can be combined with the --system, --global, and --local options
to just list the contents of those files.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar 52f1f48de6 commands: config: error out if value is unset
This makes sense, and matches git config's behavior too. Stay silent
by default, but log.dbg() what happened.

Add a test case, too.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar b0834c4b4c tests: add missing config system tests
Add basic tests for the behavior of the west.configuration APIs for
ConfigFile.SYSTEM, which were missing since we couldn't patch out the
location to somewhere safe.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar a3b9cd875d configuration: create missing config files
Add a helper to create the configuration file if it doesn't already
exist, and call it from update_config().

Add test cases for the API-level changes, which we can do now that we
can patch out all the config file locations.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar 6a3b51d3d1 configuration: fix XDG spec compliance and support BSDs
The XDG_CONFIG_HOME variable, if set, does not specify an additional
place to look for config options: it says they should go exactly
there. Fix that. Add support for BSD platforms while we are here.

To improve testability in future patches, move the code which gets the
location for a config file into a function that we can monkeypatch
later. This will make it easier to test system level config settings.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar a58e45a0bb tests: improve test_config.py coverage and readability
Improve the test coverage and make sure that the command line
interface and module API work together as documented.

Improve readability by adding helpers, decreasing verbosity, and
marking the mandatory setup fixture autouse=True to cut boilerplate.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar 775de0f48a tests: improve test_config.py timing and behavior
Instead of bothering to create a proper west init-based installation
when testing the configuration commands, use a fixture that just
creates what is needed, and also validates module-wide assumptions
instead of repeating them in each test case.

This improves the quality of the test by only testing what is needed,
helping to isolate these tests from unrelated errors in the manifest
handling code.

It also drops the test time from ~3.5 seconds to about ~2.5 seconds in
my Linux environment.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar d2cb5d6109 tests: test_config.py cosmetics
Trivial cleanups, no functional changes expected.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti Bolivar a2ae763750 tests: fix misleading conftest.py comment
We don't have west in repos_tmpdir. This is yet another old docstring
that I forgot to update when we removed the bootstrapper.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-30 11:39:05 -06:00
Marti c724ee6a62 tests: fix test_project.py on Windows
This file is giving false negatives on Windows. To fix:

- test_manifest_freeze: expect (and escape) Windows paths
- test_forall: echo may be available in cmd.exe, but single-quoted
  strings sure aren't
- test_extension_command_*: handle newlines portably

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-20 11:06:53 +02:00
Marti 624880e8ff tests: conftest: use command strings exactly on Windows
This fixes test_project.py::test_list on Windows, as otherwise quoting
and splitting the relevant paths using shlex with POSIX rules behaves
incorrectly.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-20 11:06:53 +02:00
Marti 402a10a68c tests: fix test_config.py on windows
'west config' testing is giving false negatives on Windows. To fix:

- canonicalize and fix up global config path testing
- avoid passing paths to cmd(); they don't play well with
  shlex.split() and aren't necessary to make sure the config
  command is behaving properly

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-05-20 11:06:53 +02:00