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

Environment setup can collide when .dsv files and scripts change the same env var #103

Closed
jacobperron opened this issue Oct 22, 2019 · 9 comments · Fixed by #104
Closed
Assignees
Labels
bug Something isn't working

Comments

@jacobperron
Copy link
Contributor

The new performance enhancements that involve preparing the environment in Python (#89) can subtly collide with packages that provide environments hooks as shell scripts (instead of the newer .dsv files). This can happen because the Python code is unaware any environment changes that might occur when sourcing arbitrary shell scripts.

In particular, I ran into this issue while updating ROS 2 Java packages to work with Dashing.
In an attempt to use .dsv files for setting the CLASSPATH variable, I ran into an issue that CLASSPATH previously set by ament_cmake packages are overwritten by the .dsv file-based implementation (e.g. rcljava's JARs are missing from CLASSPATH since they are appended via shell scripts earlier in the topological ordering of packages).

@jacobperron jacobperron added the bug Something isn't working label Oct 22, 2019
@dirk-thomas dirk-thomas changed the title Python-based environment setup can collide with other package hooks Environment setup can collide when .dsv files and scripts change the same env var Oct 22, 2019
@dirk-thomas
Copy link
Contributor

When prepending values to an env var we aim to not have a trailing separator. The rational is that in the past there were cases where consumers of the env vars didn't support that case.

A sourced script can perform the correct prepending. But the command generated for a dsv type like prepend-non-duplicate isn't aware of the shell logic and instead of resulting in a line like:

`FOO=new_value:$FOO`

it will (since the env var was not set before) generate a line like:

`FOO=new_value`

which will overwrite the change of the sourced script.

@jacobperron
Copy link
Contributor Author

jacobperron commented Oct 22, 2019

Just throwing out an idea, what if we always prepend and then do a post-processing step to check that all env vars that were set do not have a trailing :? And if they do, just unset them.

@dirk-thomas
Copy link
Contributor

Should that post processing happen in the shell or in Python? The former would need to be implemented in all primary shells (sh, bat, ps1 atm). The later would require the overhead of another Python invocation.

How does the post-processing determine which env vars to check? Preferably without needing to discover all .dsv file again due to the necessary runtime.

Should the post-processing distinguish which trailing separators are actually coming from the "always prepending" or blindly remove them (potentially altering values unintentionally)?

@jacobperron
Copy link
Contributor Author

jacobperron commented Oct 22, 2019

Should that post processing happen in the shell or in Python?

I guess the former seems like the way to go performance-wise.

How does the post-processing determine which env vars to check? Preferably without needing to discover all .dsv file again due to the necessary runtime.

We could store this information in a temporary environment variable (which is just a list of all variables prepended to via dsv commands). Note, this could be unset at the end of the post-processing script to avoid environment pollution.

Should the post-processing distinguish which trailing separators are actually coming from the "always prepending" or blindly remove them (potentially altering values unintentionally)?

I'm not sure, but maybe it's safest to just remove the trailing separator if and only it is the only character (ie. if the contents of the variable are longer than one character, do nothing).
It seems like an odd case to want a standalone separator, but I don't know.

@dirk-thomas
Copy link
Contributor

maybe it's safest to just remove the trailing separator if and only it is the only character

That might still break (poorly written) code which isn't capable of handling a trailing separator.

@jacobperron
Copy link
Contributor Author

We know what the first prepended value should be if nothing else was prepended before the first .dsv file was processed. A best effort approach could be to compare the suffix with what we might expect to be there, and if they're equal, remove the trailing separator.

@dirk-thomas
Copy link
Contributor

That sounds like a promising approach 👍

@jacobperron
Copy link
Contributor Author

I'll try to implement this in colcon first and see how it goes.

jacobperron added a commit to colcon/colcon-core that referenced this issue Oct 23, 2019
This resolves an issue where environment variables can collid if modified by both .dsv files and scripts.
For more detail see ament/ament_package#103

The solution is to always prepend, which will avoid overwriting a variable if previously set by a script.
Then we introduce a cleanup command for each variable prepended to in order to remove a possible trailing separator.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
@jacobperron
Copy link
Contributor Author

I took a slightly different approach in colcon/colcon-core#254,

Instead of setting an environment variable to track changes in the shell scripts, I've done this tracking in Python and appended commands for cleanup.

@jacobperron jacobperron self-assigned this Oct 23, 2019
dirk-thomas pushed a commit to colcon/colcon-core that referenced this issue Oct 24, 2019
* Always prepend with a trailing separator

This resolves an issue where environment variables can collid if modified by both .dsv files and scripts.
For more detail see ament/ament_package#103

The solution is to always prepend, which will avoid overwriting a variable if previously set by a script.
Then we introduce a cleanup command for each variable prepended to in order to remove a possible trailing separator.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Add batch command for trailing separator cleanup

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Address review

* Rename operation to "remove trailing separator"
* Make the format string definition optional
* Simplify logic to remove a trailing separator if it exists (not caring about the last value)

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Minor cleanup

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Declare and document FORMAT_STR_REMOVE_TRAILING_SEPARATOR

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Simplify template logic

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Print cleanup commands directly instead of maintain list

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Add comment explaining change

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Only cleanup for variables initially set by the Python script

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Fix lint and clarify expand documentation

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
jacobperron added a commit that referenced this issue Oct 24, 2019
Fixes #103

Resolves the issue where environment variables can collide if they are modified by both .dsv files
and scripts. See the connected issue for more detail.

The solution is to always prepend to environment variables to avoid potentially overwriting a
value set from another script. To avoid a trailing separator we introduce a cleanup command that
is run for each variable prepended to.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
jacobperron added a commit that referenced this issue Oct 25, 2019
* Always prepend with a trailing separator

Fixes #103

Resolves the issue where environment variables can collide if they are modified by both .dsv files
and scripts. See the connected issue for more detail.

The solution is to always prepend to environment variables to avoid potentially overwriting a
value set from another script. To avoid a trailing separator we introduce a cleanup command that
is run for each variable prepended to.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants