Commit Graph

512 Commits

Author SHA1 Message Date
Martí Bolívar 831b012d41 west update: add --stats option
This prints performance statistics. Zephyr wants it for figuring out
slowdowns observed in CI.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-05 09:11:33 -08:00
Martí Bolívar 4ab5c08c60 west 0.7.0rc1
At this point, the manifest schema is frozen, so we can also update
west.manifest.SCHEMA_VERSION to 0.7, as this version of west parses
anything that 0.7 will be able to parse.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-04 08:11:19 -08:00
Martí Bolívar ba9825739a manifest: fix docstring
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-04 08:11:19 -08:00
Martí Bolívar 2cfcff1816 manifest: tweak logging
"Close the parentheses" when done resolving a project import, and add
project revision information when importing from a project.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-04 08:11:19 -08:00
Martí Bolívar 92c18ac55a main: move verbose manifest logging to project.py
This kind of verbose detail about the parsed manifest is not always
useful to others.

E.g. downstream in the nRF Connect SDK, this is cluttering up the
output of a west extension that compares mainline zephyr's manifest
repository revisions with NCS's. This seems like an annoyance to me,
so this logging shouldn't be global.

We do, however, need it for debugging when resolving the manifest
and running 'west -vv update'.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-04 08:11:19 -08:00
Martí Bolívar 16e2250e45 manifest: hacky import loop detection
I keep running into edge cases trying to get proper import loop
detection going, so just catch the RecursionError it causes and
convert it to ManifestImportFailed.

Testing this takes a while, so we only will do that from CI for now.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-04 08:11:19 -08:00
Martí Bolívar 52ff93f766 manifest: factor private context into a namedtuple
I want to add more values to the private context we pass around as we
resolve the manifest, but it's annoying to do so one parameter at a
time, since it requires updating a lot of functions.

Let's make a container object for this state and pass it around instead.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:37:37 -08:00
Martí Bolívar 900711acd0 west update: don't update projects twice
Track which projects we've already updated via update_importer() and
don't do it twice if it's already done.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:37:37 -08:00
Martí Bolívar 85f2aa90ac west update: allow PROJECTs defined in manifest repo
Relax the restriction that west update cannot update individual
projects when manifest imports are in use, as long as the projects on
the command line are all defined in the manifest repository.

That's a well-defined enough operation to support, since this type of
project is basically equivalent to being defined in the top level
west.yml.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:37:37 -08:00
Martí Bolívar 1cf441d26f commands: add WestCommand.has_manifest property
This is useful for making decisions based on whether we have a
manifest.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:37:37 -08:00
Martí Bolívar 295637d4d1 manifest: add ImportFlag.IGNORE_PROJECTS
This will be useful for relaxing 'west update PROJECT' behavior.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:37:37 -08:00
Martí Bolívar 55fbe61203 west update: use project.remote_name
From a CLI user perspective this means the 'west update' behavior is
unchanged with respect to project remote names from the west 0.6.x
series.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:37:37 -08:00
Martí Bolívar cc29a46155 manifest: restore project remote names
Do not restore a full-fledged Remote class, but allow projects to
specify the name of the remote that should be used when cloning them,
and respect it in project.py.

From an API perspective this preserves the breaking change in 630f069,

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:37:37 -08:00
Martí Bolívar 70753d65f0 tests: add more end-to-end import testing
Add tests for west init and west update for:

- simple zephyr downstream with revision fixed to a tag
- zephyr downstream with tag revision and project fork
- downstream of a manifest repository which has a directory
  of submanifest files
- downstream of a zephyr rolling release

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:12:58 -08:00
Martí Bolívar 8a1de26981 tests: factor out some code into conftest
Some definitions in test_manifest.py will be useful in
test_project.py.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:12:58 -08:00
Martí Bolívar c4ff3db314 tests: clean up test_manifest.py
Remove boilerplate by adding a manifest_repo fixture and cleaning up
some unnecessary string creations. Rename the fs_topdir fixture to
tmp_workspace to more clearly describe what it is.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:12:58 -08:00
Martí Bolívar cf0ae98480 tests: add some more map import tests
These verify the general behavior of blacklist and whitelist map keys,
and make sure they propagate through nested (self) imports.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-02-03 07:12:58 -08:00
Kumar Gala 4fcbf40a6e github: Use a github action for testing
Introduce a github action that will run tox on a number of python
versions and host OSes for testing.

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
2020-01-27 08:22:47 -08:00
Martí Bolívar 54d04577a3 manifest: pass import map filters down the tree
As is already done for projects, pass the filter function implied by
an import's whitelists and blacklists down the call stack. When we
encounter a new filter due to a map import, compose the existing
filter with the new one. We use None as a signal that there is no
filter in place to avoid calling unnecessary functions.

The motivation behind this patch was to correctly log project addition
exactly once, when they are first discovered in the recursion tree.

However, it's actually necessary for correctness, and fixes a bug that
can be shown by example:

west.yml:

  manifest:
    ...
    self:
      import:
        file: foo.yml
        name-whitelist: just-this-project

foo.yml:

  manifest:
    ...
    self:
      import: bar.yml

bar.yml:

  manifest:
    ...
    projects:
    - name: just-this-project
    - name: but-not-this-one

Above, we should ultimately import just-this-project from bar.yml, and
not but-not-this-one. This implies propagating and ANDing together
filters implied by whitelists and blacklists from higher levels in the
tree.

This patch also includes a test case for this type of situation.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 56675c916c manifest: pass projects map down the tree
Pass the "known projects" map to the Manifest constructor via a kwarg.
This makes it possible to track most of the known projects when
resolving imports. That in turn partially resolves #360, except in the
case of import maps, where we are still creating a whole new manifest
and then filtering it out. We can fix that next.

This implies a hacky change to _check_paths_are_unique(): we need to
ignore checks involving the manifest repository if we're not top
level, as they may lead to false positives. In my opinion, this is yet
another good reason to avoid mixing the manifest repository itself
into the projects list.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar c7182b584f manifest: remove unnecessary Path() allocation
The git() method can take an os.PathLike.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 71aaf57045 manifest: use standard logging module
And add a shim in main.py that enables verbose debugging output if -v
is given and the manifest is re-parsed after the initial attempt is
made. (This makes commands like 'west update' and 'west manifest' emit
output when necessary.)

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 35d86a08ef manifest: remove support for rename key in map import
This feature is an artifact of an abandoned design for manifest
imports which now has unclear utility. Rip it out for now until we are
sure we need it and have thought it through.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 23b8525181 manifest: improve validate() handling
Convert TypeError to MalformedManifest to avoid a stack trace, and
improve the error message.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar fe3cba3021 manifest: remove unecessary Path() call
The repo_root value is already a Path.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar c4a3bb8cb7 manifest: refactor git checks into project commands
It's nicer for the user of the manifest library (e.g. 'west diff') to
decide what should happen if git is not available, so move some
warning calls about missing git into project.py, and add a new helper
for dealing with dying when git is not found.

This lets us keep using log.wrn() for this detection, which we are
about to stop doing from manifest.py.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 5e06d90b7c manifest: don't swallow errors in Project.is_ancestor_of
The manpage for git merge-base --is-ancestor says the return value
should be 0 or 1. Anything else is probably an actual error, which we
should propagate up.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 5cd9d8cfd1 manifest: fix AttributeError in self import
This only passed CI because we had no coverage. Now we do.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 75a416a526 manifest.py: delete stale comment
We are a Python 3.6 codebase.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 33e5c106bf project.py: don't force a git call in west manifest
As a WestCommand, this context knows its topdir. Passing this to
Manifest.from_file() is enough to avoid shelling out to git when
loading the manifest again, which we should do.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-24 18:13:57 -05:00
Martí Bolívar 2101a7af38 tox.ini: run linter first
The linter finishes in a few seconds and its errors can be addressed
quickly, whereas the test suite takes a bit longer to run. Let's do
the fast thing first.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-22 07:36:31 -05:00
Martí Bolívar e4a1e06fe1 commands.py: pacify linter
The CI linter is firing on pre-existing code from
commands/__init__.py; fix that.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-22 07:36:31 -05:00
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 82cf0e3630 .gitignore: add .coverage
This is a SQLite database of coverage data now generated by default
during testing by pycov.

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 c37f7d5f26 manifest: handle yaml's ScannerError
Malformed manifests can result in a scanner error from PyYAML. Handle
that specifically.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar 18a32fd4fc manifest: fix errors on malformed imports
We need to validate the imported data before assuming it's a
dictionary we can start doing things with. Fix that by calling out to
validate().

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar cd55fcc255 manifest: validate() fixes
We need to be a bit more careful with our types.

For example, the string "not-a-manifest" can be loaded as YAML, and
evaluates to... itself. And the string 'manifest' sure is in the
string 'not-a-manifest', so the "'manifest' not in data" check in
validate() doesn't catch the invalidity.

Then we try to index ['manifest'] in a string, which doesn't work,
because string indexes must be integers. Boom.

Fix it with extra type checking.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar 7822a4c315 manifest: fix _manifest_content_at() for trees
We need to print the contents of the directory at manifest-rev, NOT
project.revision.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar ca56fce8c8 manifest: fix a docstring
s/,/./

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar cd68a6f242 manifest: fix Project.listdir_at()
This is returning a list of lists, when it should be returning a list
of strings.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar 70a38461c8 manifest: remove dead code
Remove some dead code discovered with coverage testing:

- _import_from_project() is never called with a falsy import value.
  Add an assert to preserve the invariant.

- _quote_maybe() and _west_yml() are leftovers that should have been
  rebased out

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Martí Bolívar 55f91f4cf5 manifest: fix west command imports
The expected behavior for west commands imported from self is that
they will be added to the top level manifest, but this isn't working
due to some incorrect string/list conversions. Fix that up.

The same behavior should be extended to west command inheritance from
projects. We do allow some of that, but it's currently only bringing
in the first west-commands found in a submanifest if the project
doesn't specify commands of its own. Make the behavior more closely
match that of self-imports, except that in the case of projects, the
import order is 'reversed': parent project west-commands come before
inherited ones in order.

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 d9d43eef08 west init: fix error handling
West init's bootstrap() isn't smart enough about checking whether the
target directory has already been initialized. Fix that.

Also catch a shutil.Error and print a sensible message instead of
dumping stack.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 12:47:54 -08:00
Anas Nashif 45b91bd11e ci: move west to a different node pool
This new pool uses large nodes and suitable for anything that does not
run sanitycheck. The queue for this pool is not as a long as with the
2XL pool which will give west instant results instead of waiting for 2XL
node to finish sanitycheck.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2020-01-17 13:39:33 -05:00
Martí Bolívar 5d90ecd4ff tests: enable coverage testing for plain 'tox'
Always get coverage testing.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 17:14:36 +01: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 237d4551c8 packaging: west is no longer a namespace package
We used to require the use of namespace packages, because west was
split into a bootstrapper and per-installation clone. That hasn't been
true since 0.6.0, so stop treating west like a namespace package.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-01-17 17:14:36 +01:00