Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multimanifest prep #266

Merged
merged 15 commits into from
May 20, 2019
Merged

Conversation

mbolivar
Copy link
Contributor

Prep work commits for the multimanifest work.

The main changes needed to enable multimanifest are:

  • manifest: support explicit project URLs
  • manifest: project names must be unique

The rest are just cleanup and minor things.

There's no good reason to have these tests in subdirectories. Flatten
them out. Keep the directory of invalid manifests separate to keep the
directory listing clean, though.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
It's not clear what this is doing here. It doesn't begin with "test",
so it's not being tested, and it seems to be a copy of test_config.py
with some important features needed to avoid modifying the user's
configuration.

Delete it.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
Don't copy the west tree; tox already installs it for us into the new
virtualenv, and we don't run any code out of a checked out repository
anymore, so doing things related to that is unnecessary.

This also makes the tests run a little bit faster (around a 5% or more
speedup on my system).

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
It takes 20 seconds on my machine to run the full set of tests, which
is slow enough that testing breaks me out of flow state.

On the suspicion that creating git repositories and using the file://
protocol when cloning (which prevents use of hardlinks) is slowing
things down, use some pytest features to avoid creating git
repositories repeatedly. Also let git use hardlinks when they are
available when cloning repositories.

On my system, this brings the average of 10 runs from 20.129 seconds
spent testing to 17.649, a 12% improvement overall. Still not ideal,
but not worth throwing away, either.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
I'm not sure this ever worked; the args field is an empty tuple even
in Python 3.4. Use cmd and returncode attributes appropriately
instead.

Don't offer the 'for a stack trace' message here anymore: this doesn't
indicate a west error, which is what that is meant to capture.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
Add a helper for saving the current traceback to a temporary file and
use it appropriately from the exception handlers in main(), This avoid
throwing away information in case the error was nondeterministic.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
We're going to add explicit project URLs to the manifest, so the
remote should no longer be a positional.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
Allow each project element to explicitly specify its URL. This avoids
forcing users to name projects according to their URLs, which can be
inconvenient (and prevents us from enforcing a rule that project names
are unique).

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
We don't apply the west default revision correctly if defaults is
None. Since we find it convenient to let west figure out the defaults
for us, demote it to a kwarg as well and let it be None more gracefully.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
@mbolivar
Copy link
Contributor Author

@tejlmand regarding tests: remove empty_config.py; any insight into why it was added? Just the result of git commit -a or so?

Make sure to update comments for existing tests with modified semantics.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
It is always possible to satisfy this constraint now that project URLs
may be specified explicitly.

(This restriction will be necessary to make manifest imports work
sensibly -- we should have done this before...).

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
We need a common definition for canonicalizing paths; the lack of one
is causing issues on Windows.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
'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>
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>
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>
@mbolivar
Copy link
Contributor Author

Added some additional fixes to get all our tests passing on Windows 10 as well.

@@ -557,12 +557,10 @@ def main(argv=None):
except KeyboardInterrupt:
sys.exit(0)
except CalledProcessError as cpe:
log.err('command exited with status {}: {}'.format(
cpe.args[0], quote_sh_list(cpe.args[1])))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can guarantee this worked, I tested it explicitly. That said, this is the right way to do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. This change is what we discussed in previous PRs, so that users who initialize CalledProcessError with kwargs instead of positionals don't get faced with an IndexError when we try to access cpe.args.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IOW: I know you're not asking for a change here, but you specifically asked for this change earlier :). Even though it "works" if you properly initialize CalledProcessError as the python subprocess module does, users who make their own instances won't always, as we discovered.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change is required and I am completely happy with it. I am just saying that this old code actually worked, to my amazement :)

traceback.print_exc()
else:
log.inf(for_stack_trace)
log.err(msg, 'See {} for a traceback.'.format(dump_traceback()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I like this.

@@ -281,6 +282,10 @@ def _load(self, data):
except ValueError as ve:
self._malformed(ve.args[0])

# Project names must be unique.
if project.name in project_names:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this fix a GitHub issue? I seem to recall there was one

Copy link
Contributor Author

@mbolivar mbolivar May 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is essential to the design of the multimanifest feature. Projects are identified by their names in that work; it's how we decide what projects to apply overrides of attributes like url, name, etc. to. This means it doesn't make sense to continue allowing two projects with the same "name" in a single manifest. Arguably it never did, but it was necessary before because some projects might have had the same final path component in a URL but different URL bases. That case can be handled now with an explicit url: for at least one of the two.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, thanks for the explanation

cmdlst = shlex.split('west ' + cmd)
print('running:', cmdlst)
cmd = 'west ' + cmd
if platform.system() != 'Windows':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We typically use sys.platform, maybe use that for consistency

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed btw? We don't usually make this difference in normal invokations of check_output et al.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We typically use sys.platform, maybe use that for consistency

Really? We use platform.system() in configuration.py ,which is what this is testing. I can make that change, though.

Why is this needed btw? We don't usually make this difference in normal invokations of check_output et al.

It's breaking the tests because shlex splits by POSIX rules, which isn't right for windows shells and led to bad results when applied to paths. Example:

In [2]: shlex.split('west foo bar\\baz')
Out[2]: ['west', 'foo', 'barbaz']

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I see. I don't have a strong preference either way, just wanted to keep it consistent. I didn't know we used platform.system() in configuration.py, but I've always seen sys.platform elsewhere, like the tox.ini or the requirements.txt.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 years later, dropping shlex.split() in #730

Copy link
Member

@carlescufi carlescufi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minus some minor nits, I am happy with this. Thanks!

@carlescufi carlescufi merged commit c724ee6 into zephyrproject-rtos:master May 20, 2019
marc-hb added a commit to marc-hb/west that referenced this pull request Aug 28, 2024
Stop using `shlex.split()` in conftest.py as a way to prepare test
commands for subprocess.run() because it does not always work. When we
have quoting issues, just avoid them entirely by passing the test
command as a list.

Replace shlex.split() with a simple str.split() for convenience in
simple cases. This simple split() will immediately fail when trying to
use quote which is working exactly as intended.

This also makes the cmd() interface more similar to subprocess.run() and
its many friends, which is good thing.

This is similar to commit 4100764 ("Project.git(list/str): reduce
reliance on shlex.split()") but applied to tests/

Before commit 624880e, shlex.split() was used unconditionally in
conftest.py. As expected, this eventually broke on Windows: shlex is
not compatible across all operating systems and shells.

https://docs.python.org/3/library/subprocess.html#security-considerations

> If the shell is invoked explicitly, via shell=True, it is the
> application’s responsibility to ensure that all whitespace and
> metacharacters are quoted appropriately to avoid shell injection
> vulnerabilities. On _some_ platforms, it is possible to use shlex.quote()
> for this escaping.

(Emphasis mine)

Then commit 624880e made the "interesting" decision to stop using
shlex.split()... only on Windows. This was discussed in
zephyrproject-rtos#266 (comment)

So after this commit, parsing of test commands was delegated to the
shell but... only on Windows! This worked for a long time but eventually
broke testing white spaces for the new `west alias` zephyrproject-rtos#716. Rather than
making that Windows-specific hack even more complex with a special case,
finally do the right thing and ask more complex test commands to use a
list. Now we can drop shlex.

Signed-off-by: Marc Herbert <marc.herbert@intel.com>
marc-hb added a commit to marc-hb/west that referenced this pull request Aug 28, 2024
Stop using `shlex.split()` in conftest.py as a way to prepare test
commands for subprocess.run() because it does not always work. When we
have quoting issues, just avoid them entirely by passing the test
command as a list.

Replace shlex.split() with a simple str.split() for convenience in
simple cases. This simple split() will immediately fail when trying to
use quote which is working exactly as intended.

This also makes the cmd() interface more similar to subprocess.run() and
its many friends, which is good thing.

This is similar to commit 4100764 ("Project.git(list/str): reduce
reliance on shlex.split()") but applied to tests/

Before commit 624880e, shlex.split() was used unconditionally in
conftest.py. As expected, this eventually broke on Windows: shlex is
not compatible across all operating systems and shells.

https://docs.python.org/3/library/subprocess.html#security-considerations

> If the shell is invoked explicitly, via shell=True, it is the
> application’s responsibility to ensure that all whitespace and
> metacharacters are quoted appropriately to avoid shell injection
> vulnerabilities. On _some_ platforms, it is possible to use shlex.quote()
> for this escaping.

(Emphasis mine)

Then commit 624880e made the "interesting" decision to stop using
shlex.split()... only on Windows. This was discussed in
zephyrproject-rtos#266 (comment)

So after this commit, parsing of test commands was delegated to the
shell but... only on Windows! This worked for a long time but eventually
broke testing white spaces for the new `west alias` zephyrproject-rtos#716. Rather than
making that Windows-specific hack even more complex with a special case,
finally do the right thing and ask more complex test commands to use a
list. Now we can drop shlex.

Signed-off-by: Marc Herbert <marc.herbert@intel.com>
marc-hb added a commit that referenced this pull request Aug 29, 2024
Stop using `shlex.split()` in conftest.py as a way to prepare test
commands for subprocess.run() because it does not always work. When we
have quoting issues, just avoid them entirely by passing the test
command as a list.

Replace shlex.split() with a simple str.split() for convenience in
simple cases. This simple split() will immediately fail when trying to
use quote which is working exactly as intended.

This also makes the cmd() interface more similar to subprocess.run() and
its many friends, which is good thing.

This is similar to commit 4100764 ("Project.git(list/str): reduce
reliance on shlex.split()") but applied to tests/

Before commit 624880e, shlex.split() was used unconditionally in
conftest.py. As expected, this eventually broke on Windows: shlex is
not compatible across all operating systems and shells.

https://docs.python.org/3/library/subprocess.html#security-considerations

> If the shell is invoked explicitly, via shell=True, it is the
> application’s responsibility to ensure that all whitespace and
> metacharacters are quoted appropriately to avoid shell injection
> vulnerabilities. On _some_ platforms, it is possible to use shlex.quote()
> for this escaping.

(Emphasis mine)

Then commit 624880e made the "interesting" decision to stop using
shlex.split()... only on Windows. This was discussed in
#266 (comment)

So after this commit, parsing of test commands was delegated to the
shell but... only on Windows! This worked for a long time but eventually
broke testing white spaces for the new `west alias` #716. Rather than
making that Windows-specific hack even more complex with a special case,
finally do the right thing and ask more complex test commands to use a
list. Now we can drop shlex.

Signed-off-by: Marc Herbert <marc.herbert@intel.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants