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

new EnvVars docs #2279

Merged
merged 1 commit into from Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions reference/conanfile/tools/env.rst
@@ -1,10 +1,15 @@
conan.tools.env
===============

.. warning::

These tools are **experimental** and subject to breaking changes.


.. toctree::
:maxdepth: 2

env/environment
env/envvars
env/virtualbuildenv
env/virtualrunenv
155 changes: 40 additions & 115 deletions reference/conanfile/tools/env/environment.rst
Expand Up @@ -8,19 +8,12 @@ Environment
This is a **very experimental** feature and it will have breaking changes in future releases.


``Environment`` is a class that helps defining modifications to the environment variables.
``Environment`` is a generic class that helps defining modifications to the environment variables.
This class is used by other tools like the :ref:`conan.tools.gnu<conan_tools_gnu>` autotools helpers and
the :ref:`VirtualBuildEnv<conan_tools_env_virtualbuildenv>` and :ref:`VirtualRunEnv<conan_tools_env_virtualrunenv>`
generator.

Constructor
+++++++++++

.. code:: python

def __init__(self, conanfile):

- ``conanfile``: the current recipe object. Always use ``self``.
generator. It is important to highlight that this is a generic class, to be able to use it, a specialization
for the current context (shell script, bat file, path separators, etc), a ``EnvVars`` object needs to be obtained
from it.


Variable declaration
Expand All @@ -30,18 +23,18 @@ Variable declaration

from conan.tools.env import Environment

env = Environment(self)
env.define("MYVAR1", "MyValue1") # Overwrite previously existing MYVAR1 with new value
env.append("MYVAR2", "MyValue2") # Append to existing MYVAR2 the new value
env.prepend("MYVAR3", "MyValue3") # Prepend to existing MYVAR3 the new value
env.remove("MYVAR3", "MyValue3") # Remove the MyValue3 from MYVAR3
env.unset("MYVAR4") # Remove MYVAR4 definition from environment


# And the equivalent with paths
env.define_path("MYPATH1", "path/one") # Overwrite previously existing MYPATH1 with new value
env.append_path("MYPATH2", "path/two") # Append to existing MYPATH2 the new value
env.prepend_path("MYPATH3", "path/three") # Prepend to existing MYPATH3 the new value
def generate(self):
env = Environment()
env.define("MYVAR1", "MyValue1") # Overwrite previously existing MYVAR1 with new value
env.append("MYVAR2", "MyValue2") # Append to existing MYVAR2 the new value
env.prepend("MYVAR3", "MyValue3") # Prepend to existing MYVAR3 the new value
env.remove("MYVAR3", "MyValue3") # Remove the MyValue3 from MYVAR3
env.unset("MYVAR4") # Remove MYVAR4 definition from environment

# And the equivalent with paths
env.define_path("MYPATH1", "path/one") # Overwrite previously existing MYPATH1 with new value
env.append_path("MYPATH2", "path/two") # Append to existing MYPATH2 the new value
env.prepend_path("MYPATH3", "path/three") # Prepend to existing MYPATH3 the new value

The "normal" variables (the ones declared with ``define``, ``append`` and ``prepend``) will be appended with a space,
by default, but the ``separator`` argument can be provided to define a custom one.
Expand All @@ -59,118 +52,51 @@ Environments can be composed:

from conan.tools.env import Environment

env1 = Environment(self)
env1 = Environment()
env1.define(...)
env2 = Environment(self)
env2 = Environment()
env2.append(...)

env1.compose(env2) # env1 has priority, and its modifications will prevail


Creating launcher files
+++++++++++++++++++++++
env1.compose_env(env2) # env1 has priority, and its modifications will prevail

Environments can generate launcher files:

.. code:: python

def generate(self):
env1 = Environment(self)
env1.define("foo", "var")
env1.save_script("my_launcher")


Although it potentially could be used in other methods, this functionality is intended to work in the ``generate()``
method.

It will generate automatically a ``my_launcher.bat`` for Windows systems or ``my_launcher.sh`` otherwise.

Also, by default, Conan will automatically append that launcher file path to a list that will be used to
create a ``conanbuild.bat|sh`` file aggregating all the launchers in order. The ``conanbuild.sh/bat`` launcher
will be created after the execution of the ``generate()`` method.

The ``conanbuild.bat/sh`` launcher will be executed by default before calling every ``self.run()`` command. This
would be typically done in the ``build()`` method.

You can change the default launcher with the ``env`` argument:

.. code:: python

...
def build(self):
# This will automatically wrap the "foo" command with the correct launcher:
# my_launcher.sh && foo
self.run("foo", env=["my_launcher"])

The ``group`` argument (``"build"`` by default) can be used to define different groups of environment files, to
aggregate them separately. For example, using a ``group="run"``, like the ``VirtualRunEnv`` generator does, will
aggregate and create a ``conanrun.bat|sh`` script:

.. code:: python

def generate(self):
env1 = Environment(self)
env1.define("foo", "var")
# Will append "my_launcher" to "conanrun.bat|sh"
env1.save_script("my_launcher", group="run")


You can also use ``group=None`` argument to avoid appending the script to the aggregated ``conanbuild.bat|sh``:

.. code:: python

env1 = Environment(self)
env1.define("foo", "var")
# Will not append "my_launcher" to "conanbuild.bat|sh"
env1.save_script("my_launcher", group=None)



Applying the environment
++++++++++++++++++++++++
Obtaining environment variables
++++++++++++++++++++++++++++++++

As an alternative to a launcher, environments can be applied in the python environment, but the usage
of the launchers is recommended if possible:
You can obtain an ``EnvVars`` object with the ``vars()`` method like this:

.. code:: python

from conan.tools.env import Environment

env1 = Environment(self)
env1.define("foo", "var")
with env1.apply():
# Here os.getenv("foo") == "var"
...

Iterating the Environment object
++++++++++++++++++++++++++++++++

You can iterate an Environment object like this:

.. code:: python
def generate(self):
env = Environment()
env.define("MYVAR1", "MyValue1")
envvars = env.vars(self, scope="build")
# use the envvars object

env1 = Environment()
env1.append("foo", "var")
env1.append("foo", "var2")
for name, value in env.items():
assert name == "foo":
assert value == "var var2"
The default ``scope`` is equal ``"build"``, which means that if this ``envvars`` generate a script to
activate the variables, such script will be automatically added to the ``conanbuild.sh|bat`` one, for
users and recipes convenience. Conan generators use ``build`` and ``run`` scope, but it might be possible
to manage other scopes too.


Other Environment usage
++++++++++++++++++++++++
Environment definition
++++++++++++++++++++++

There are some other places where this ``Environment`` is used internally by Conan:
There are some other places where ``Environment`` can be defined and used:

- In recipes ``package_info()`` method, in new ``self.buildenv_info`` and ``self.runenv_info``.
- In generators like ``AutootoolsDeps``, ``AutotoolsToolchain``, that need to define environment.
- In profiles new ``[buildenv]`` and ``[runenv]`` sections.
- In recipes ``package_info()`` method, in new ``self.buildenv_info`` and ``self.runenv_info``, this
environment will be propagated via ``VirtualBuildEnv`` and ``VirtualRunEnv`` respectively to packages
depending on this recipe.
- In generators like ``AutootoolsDeps``, ``AutotoolsToolchain``, that need to define environment for the
current recipe.
- In profiles new ``[buildenv]`` section.


The definition in ``package_info()`` is as follow, taking into account that both ``self.buildenv_info`` and ``self.runenv_info``
are objects of ``Environment()`` class.


.. code:: python

from conans import ConanFile
Expand All @@ -189,4 +115,3 @@ are objects of ``Environment()`` class.
# at runtime
self.runenv_info.define("MYPKG_DATA_DIR", os.path.join(self.package_folder,
"datadir"))

109 changes: 109 additions & 0 deletions reference/conanfile/tools/env/envvars.rst
@@ -0,0 +1,109 @@
EnvVars
=======

.. warning::

This is a **very experimental** feature and it will have breaking changes in future releases.


``EnvVars`` is a class that represents an instance of environment variables for a given system.
It is obtained from the generic ``Environment`` class.

This class is used by other tools like the :ref:`conan.tools.gnu<conan_tools_gnu>` autotools helpers and
the :ref:`VirtualBuildEnv<conan_tools_env_virtualbuildenv>` and :ref:`VirtualRunEnv<conan_tools_env_virtualrunenv>`
generator.


Creating launcher files
+++++++++++++++++++++++

``EnvVars`` object can generate launcher (shell or bat scripts) files:

.. code:: python

def generate(self):
env1 = Environment(self)
env1.define("foo", "var")
envvars = env1.vars(self)
env1.save_script("my_launcher")


Although it potentially could be used in other methods, this functionality is intended to work in the ``generate()``
method.

It will generate automatically a ``my_launcher.bat`` for Windows systems or ``my_launcher.sh`` otherwise.

Also, by default, Conan will automatically append that launcher file path to a list that will be used to
create a ``conanbuild.bat|sh`` file aggregating all the launchers in order. The ``conanbuild.sh/bat`` launcher
will be created after the execution of the ``generate()`` method.

The ``conanbuild.bat/sh`` launcher will be executed by default before calling every ``self.run()`` command. This
would be typically done in the ``build()`` method.

You can change the default launcher with the ``env`` argument:

.. code:: python

...
def build(self):
# This will automatically wrap the "foo" command with the correct launcher:
# my_launcher.sh && foo
self.run("foo", env=["my_launcher"])

The ``scope`` argument (``"build"`` by default) can be used to define different scope of environment files, to
aggregate them separately. For example, using a ``scope="run"``, like the ``VirtualRunEnv`` generator does, will
aggregate and create a ``conanrun.bat|sh`` script:

.. code:: python

def generate(self):
env1 = Environment(self)
env1.define("foo", "var")
envvars = env1.vars(self, scope="run")
# Will append "my_launcher" to "conanrun.bat|sh"
envvars.save_script("my_launcher")


You can also use ``scope=None`` argument to avoid appending the script to the aggregated ``conanbuild.bat|sh``:

.. code:: python

env1 = Environment(self)
env1.define("foo", "var")
# Will not append "my_launcher" to "conanbuild.bat|sh"
envvars = env1.vars(self, scope=None)
envvars.save_script("my_launcher")



Applying the environment variables
++++++++++++++++++++++++++++++++++

As an alternative to a launcher, environments can be applied in the python environment, but the usage
of the launchers is recommended if possible:

.. code:: python

from conan.tools.env import Environment

env1 = Environment(self)
env1.define("foo", "var")
envvars = env1.vars(self)
with envvars.apply():
# Here os.getenv("foo") == "var"
...

Iterating the variables
+++++++++++++++++++++++

You can iterate an ``EnvVars`` object like this:

.. code:: python

env1 = Environment()
env1.append("foo", "var")
env1.append("foo", "var2")
envvars = env1.vars(self)
for name, value in envvars.items():
assert name == "foo":
assert value == "var var2"
12 changes: 7 additions & 5 deletions reference/conanfile/tools/env/virtualbuildenv.rst
Expand Up @@ -52,14 +52,16 @@ will create the following files:
like PATH, LD_LIBRARY_PATH, etc, and any other variable defined in the dependencies ``buildenv_info``
corresponding to the ``build`` context, and to the current installed
configuration. If a repeated call is done with other settings, a different file will be created.
After the execution or sourcing of this file, a new deactivation script will be generated, capturing the current
environment, so the environment can be restored when desired. The file will be named also following the
current active configuration, like ``deactivate_conanbuildenv-release-x86_64.bat``.
- conanbuild.(bat|sh): Accumulates the calls to one or more other scripts, in case there are multiple tools
in the generate process that create files, to give one single convenient file for all. This only calls
the latest specific configuration one, that is, if ``conan install`` is called first for Release build type,
and then for Debug, ``conanbuild.(bat|sh)`` script will call the Debug one.
- deactivate_conanbuild.(bat|sh): Accumulates the deactivation calls defined in the above ``conanbuild.(bat|sh)``.
This file should only be called after the accumulated activate has been called first.

After the execution of one of those files, a new deactivation script will be generated, capturing the current
environment, so the environment can be restored when desired. The file will be named also following the
current active configuration, like ``deactivate_conanbuildenv-release-x86_64.bat``.

Constructor
+++++++++++
Expand All @@ -76,10 +78,10 @@ generate()

.. code:: python

def generate(self, group="build"):
def generate(self, scope="build"):


Parameters:

* **group** (Defaulted to ``"build"``): Add the launcher automatically to the ``conanbuild`` launcher. Read more
* **scope** (Defaulted to ``"build"``): Add the launcher automatically to the ``conanbuild`` launcher. Read more
in the :ref:`Environment documentation <conan_tools_env_environment_model>`.
4 changes: 2 additions & 2 deletions reference/conanfile/tools/env/virtualrunenv.rst
Expand Up @@ -75,10 +75,10 @@ generate()

.. code:: python

def generate(self, group="run"):
def generate(self, scope="run"):


Parameters:

* **group** (Defaulted to ``run``): Add the launcher automatically to the ``conanrun`` launcher. Read more
* **scope** (Defaulted to ``run``): Add the launcher automatically to the ``conanrun`` launcher. Read more
in the :ref:`Environment documentation <conan_tools_env_environment_model>`.
4 changes: 2 additions & 2 deletions reference/conanfile/tools/microsoft.rst
Expand Up @@ -304,9 +304,9 @@ generate()

.. code:: python

def generate(self, group="build"):
def generate(self, scope="build"):

Parameters:

* **group** (Defaulted to ``"build"``): Add the launcher automatically to the ``conanbuild`` launcher. Read more
* **scope** (Defaulted to ``"build"``): Add the launcher automatically to the ``conanbuild`` launcher. Read more
in the :ref:`Environment documentation <conan_tools_env_environment_model>`.