diff --git a/conda_devenv/devenv.py b/conda_devenv/devenv.py index aad9646..6180809 100644 --- a/conda_devenv/devenv.py +++ b/conda_devenv/devenv.py @@ -12,12 +12,29 @@ def render_jinja(contents, filename, is_included): import sys import platform + iswin = sys.platform.startswith('win') + islinux = sys.platform.startswith('linux') + isosx = sys.platform.startswith('darwin') + + is32bit = '32bit' == platform.architecture()[0] + is64bit = not is32bit + jinja_dict = { "is_included": is_included, "os": os, "platform": platform, "root": os.path.dirname(os.path.abspath(filename)), "sys": sys, + "x86": 'x86' == platform.machine(), + "x86_64": 'x86_64' == platform.machine(), + "linux": islinux, + "linux32": islinux and is32bit, + "linux64": islinux and is64bit, + "osx": isosx, + "unix": islinux or isosx, + "win": iswin, + "win32": iswin and is32bit, + "win64": iswin and is64bit, } return jinja2.Template(contents).render(**jinja_dict) diff --git a/docs/index.rst b/docs/index.rst index 804df6c..f07c62f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,7 +1,65 @@ Welcome to conda-devenv's documentation! ======================================== +Overview +-------- + +With ``conda-devenv``, we help you manage software dependencies across Linux, Windows, and macOS +operating systems using a *single conda dependency file* ``environment.devenv.yml`` +instead of multiple ``environment.yml`` files. + +See example below: + +.. code-block:: yaml + + name: mylib + + dependencies: + - cmake + - eigen + - pip: + - sphinx + {% if linux %} + - gxx_linux-64=7.3.0 + {% endif %} + + {% if unix %} + - ccache + {% endif %} + + {% if win %} + - clcache + {% endif %} + + environment: + CPATH: + - $CONDA_PREFIX/include + + LD_LIBRARY_PATH: + - $CONDA_PREFIX/lib + +By executing: + +.. code:: + + conda devenv + +in the root of the project directory, an ``environment.yml`` file is produced. +We can now activate the conda environment ``mylib`` as follows: + +.. code:: + + conda activate mylib + +This will not only resolve the dependencies for the current operating system, +but also set environment variables ``CPATH`` and ``LD_LIBRARY_PATH`` to the +list of paths specified in the ``environment.devenv.yml`` file. + +Continue reading to learn more about the full capabilities of ``conda-devenv``! + + Contents: +--------- .. toctree:: :maxdepth: 2 diff --git a/docs/usage.rst b/docs/usage.rst index 75be2b5..69c5a5c 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -20,17 +20,56 @@ based python version, etc. For example: name: web-ui-py{{ conda_py }} dependencies: - {% if sys.platform.startswith('linux') %} + - boost + - cmake + {% if linux %} - gcc {% endif %} + {% if unix %} + - ccache + {% endif %} + {% if win %} + - clcache + {% endif %} +Note that in the example above, we are able to define dependency requirements +that are specific to Linux, macOS, and Windows (e.g., ``ccache`` is needed in +Linux and macOS, whereas ``clcache`` is needed in Windows). This is one of the +most useful capabilities of ``conda-devenv``. The following variables are available in the Jira 2 namespace: -* ``root``: this is the full path to the directory containing the ``environment.devenv.yml`` file; -* ``os``: standard module; -* ``sys``: standard module; -* ``platform``: standard module; +.. list-table:: + :widths: 20 80 + + * - ``root`` + - The full path to the directory containing the ``environment.devenv.yml`` file. + * - ``os`` + - The standard Python module object ``os`` obtained with ``import os``. + * - ``sys`` + - The standard Python module object ``sys`` obtained with ``import sys``. + * - ``platform`` + - The standard Python module object ``platform`` obtained with ``import platform``. + * - ``x86`` + - True if the system architecture is x86, both 32-bit and 64-bit, for Intel or AMD chips. + * - ``x86_64`` + - True if the system architecture is x86_64, which is 64-bit, for Intel or AMD chips. + * - ``linux`` + - True if the platform is Linux. + * - ``linux32`` + - True if the platform is Linux and the Python architecture is 32-bit. + * - ``linux64`` + - True if the platform is Linux and the Python architecture is 64-bit. + * - ``osx`` + - True if the platform is macOS. + * - ``unix`` + - True if the platform is either macOS or Linux. + * - ``win`` + - True if the platform is Windows. + * - ``win32`` + - True if the platform is Windows and the Python architecture is 32-bit. + * - ``win64`` + - True if the platform is Windows and the Python architecture is 64-bit. Environment Variables diff --git a/tests/test_jinja.py b/tests/test_jinja.py index b3ff3d8..104a3eb 100644 --- a/tests/test_jinja.py +++ b/tests/test_jinja.py @@ -61,6 +61,126 @@ def test_jinja_platform(monkeypatch): assert render_jinja(template, filename="", is_included=False) == platform.python_revision() +def test_jinja_x86(monkeypatch): + template = "{{ x86 }}" + + monkeypatch.setattr(platform, 'machine', lambda: 'x86') + assert render_jinja(template, filename="", is_included=False) == 'True' + + monkeypatch.setattr(platform, 'machine', lambda: 'x86_64') + assert render_jinja(template, filename="", is_included=False) == 'False' + + +def test_jinja_x86_64(monkeypatch): + template = "{{ x86_64 }}" + + monkeypatch.setattr(platform, 'machine', lambda: 'x86') + assert render_jinja(template, filename="", is_included=False) == 'False' + + monkeypatch.setattr(platform, 'machine', lambda: 'x86_64') + assert render_jinja(template, filename="", is_included=False) == 'True' + + +def test_jinja_linux(monkeypatch): + template = "{{ linux }}" + + monkeypatch.setattr(sys, 'platform', 'linux') + assert render_jinja(template, filename="", is_included=False) == 'True' + + monkeypatch.setattr(sys, 'platform', 'win') + assert render_jinja(template, filename="", is_included=False) == 'False' + + monkeypatch.setattr(sys, 'platform', 'darwin') + assert render_jinja(template, filename="", is_included=False) == 'False' + + +def test_jinja_linux32(monkeypatch): + template = "{{ linux32 }}" + + monkeypatch.setattr(sys, 'platform', 'linux') + + monkeypatch.setattr(platform, 'architecture', lambda: ('32bit', '')) + assert render_jinja(template, filename="", is_included=False) == 'True' + + monkeypatch.setattr(platform, 'architecture', lambda: ('64bit', '')) + assert render_jinja(template, filename="", is_included=False) == 'False' + + +def test_jinja_linux64(monkeypatch): + template = "{{ linux64 }}" + + monkeypatch.setattr(sys, 'platform', 'linux') + + monkeypatch.setattr(platform, 'architecture', lambda: ('32bit', '')) + assert render_jinja(template, filename="", is_included=False) == 'False' + + monkeypatch.setattr(platform, 'architecture', lambda: ('64bit', '')) + assert render_jinja(template, filename="", is_included=False) == 'True' + + +def test_jinja_osx(monkeypatch): + template = "{{ osx }}" + + monkeypatch.setattr(sys, 'platform', 'linux') + assert render_jinja(template, filename="", is_included=False) == 'False' + + monkeypatch.setattr(sys, 'platform', 'win') + assert render_jinja(template, filename="", is_included=False) == 'False' + + monkeypatch.setattr(sys, 'platform', 'darwin') + assert render_jinja(template, filename="", is_included=False) == 'True' + + +def test_jinja_unix(monkeypatch): + template = "{{ unix }}" + + monkeypatch.setattr(sys, 'platform', 'linux') + assert render_jinja(template, filename="", is_included=False) == 'True' + + monkeypatch.setattr(sys, 'platform', 'win') + assert render_jinja(template, filename="", is_included=False) == 'False' + + monkeypatch.setattr(sys, 'platform', 'darwin') + assert render_jinja(template, filename="", is_included=False) == 'True' + + +def test_jinja_win(monkeypatch): + template = "{{ win }}" + + monkeypatch.setattr(sys, 'platform', 'linux') + assert render_jinja(template, filename="", is_included=False) == 'False' + + monkeypatch.setattr(sys, 'platform', 'win') + assert render_jinja(template, filename="", is_included=False) == 'True' + + monkeypatch.setattr(sys, 'platform', 'darwin') + assert render_jinja(template, filename="", is_included=False) == 'False' + + +def test_jinja_win32(monkeypatch): + template = "{{ win32 }}" + + monkeypatch.setattr(sys, 'platform', 'win') + + monkeypatch.setattr(platform, 'architecture', lambda: ('32bit', '')) + assert render_jinja(template, filename="", is_included=False) == 'True' + + monkeypatch.setattr(platform, 'architecture', lambda: ('64bit', '')) + assert render_jinja(template, filename="", is_included=False) == 'False' + + +def test_jinja_win64(monkeypatch): + template = "{{ win64 }}" + + monkeypatch.setattr(sys, 'platform', 'win') + + monkeypatch.setattr(platform, 'architecture', lambda: ('32bit', '')) + assert render_jinja(template, filename="", is_included=False) == 'False' + + monkeypatch.setattr(platform, 'architecture', lambda: ('64bit', '')) + assert render_jinja(template, filename="", is_included=False) == 'True' + + def test_jinja_invalid_template(): with pytest.raises(jinja2.exceptions.TemplateSyntaxError): render_jinja(