diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2b1f0570c..31bbdef95 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,44 +40,44 @@ jobs: include: # UBUNTU - os: ubuntu-latest - python-version: "3.9" + python-version: "3.10" conda-standalone: conda-standalone - os: ubuntu-latest - python-version: "3.10" + python-version: "3.11" conda-standalone: conda-standalone-nightly - os: ubuntu-latest - python-version: "3.11" + python-version: "3.12" conda-standalone: micromamba - os: ubuntu-latest - python-version: "3.12" + python-version: "3.13" conda-standalone: conda-standalone-onedir check-docs-schema: true # MACOS - os: macos-15-intel - python-version: "3.9" + python-version: "3.10" conda-standalone: conda-standalone-nightly - os: macos-15-intel - python-version: "3.10" + python-version: "3.11" conda-standalone: conda-standalone-onedir - os: macos-latest - python-version: "3.11" + python-version: "3.12" conda-standalone: conda-standalone - os: macos-latest - python-version: "3.12" + python-version: "3.13" conda-standalone: micromamba # WINDOWS - os: windows-2022 - python-version: "3.9" + python-version: "3.10" conda-standalone: conda-standalone-nightly - os: windows-2022 - python-version: "3.10" + python-version: "3.11" conda-standalone: conda-standalone - os: windows-2022 - python-version: "3.11" + python-version: "3.12" # conda-standalone: micromamba conda-standalone: conda-standalone-nightly - os: windows-2022 - python-version: "3.12" + python-version: "3.13" # conda-standalone: micromamba conda-standalone: conda-standalone-onedir @@ -168,7 +168,7 @@ jobs: python constructor/_schema.py git diff --exit-code - name: Upload the example installers as artifacts - if: github.event_name == 'pull_request' && matrix.python-version == '3.9' + if: github.event_name == 'pull_request' && matrix.python-version == '3.10' uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: installers-${{ runner.os }}-${{ github.sha }}-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }} diff --git a/constructor/_schema.py b/constructor/_schema.py index d50cac46a..a8ae97514 100644 --- a/constructor/_schema.py +++ b/constructor/_schema.py @@ -188,13 +188,13 @@ class LicensesBuildOutput(BaseModel): licenses: _LicensesBuildOutputOptions -BuildOutputConfigs: TypeAlias = Union[ - HashBuildOutput, - InfoJsonBuildOutput, - PkgsListBuildOutput, - LockfileBuildOutput, - LicensesBuildOutput, -] +BuildOutputConfigs: TypeAlias = ( + HashBuildOutput + | InfoJsonBuildOutput + | PkgsListBuildOutput + | LockfileBuildOutput + | LicensesBuildOutput +) class ConstructorConfiguration(BaseModel): diff --git a/examples/extra_envs/construct.yaml b/examples/extra_envs/construct.yaml index ef09adfcd..e7370e72c 100644 --- a/examples/extra_envs/construct.yaml +++ b/examples/extra_envs/construct.yaml @@ -7,15 +7,15 @@ installer_type: all channels: - https://conda.anaconda.org/conda-forge specs: - - python=3.9 + - python=3.10 - conda # conda is required for extra_envs - miniforge_console_shortcut 1.* # [win] exclude: # [unix] - tk # [unix] extra_envs: - py310: + py311: specs: - - python=3.10 + - python=3.11 - pip channels: - conda-forge @@ -33,10 +33,10 @@ build_outputs: - info.json - pkgs_list - pkgs_list: - env: py310 + env: py311 - lockfile - lockfile: - env: py310 + env: py311 - licenses: include_text: True text_errors: replace diff --git a/examples/extra_envs/test_install.bat b/examples/extra_envs/test_install.bat index ecf8eeed7..d2d4336a5 100644 --- a/examples/extra_envs/test_install.bat +++ b/examples/extra_envs/test_install.bat @@ -1,12 +1,12 @@ echo Added by test-install script > "%PREFIX%\test_install_sentinel.txt" -:: base env has python 3.9 +:: base env has python 3.10 if not exist "%PREFIX%\conda-meta\history" exit 1 -"%PREFIX%\python.exe" -c "from sys import version_info; assert version_info[:2] == (3, 9)" || goto :error +"%PREFIX%\python.exe" -c "from sys import version_info; assert version_info[:2] == (3, 10)" || goto :error -:: extra env named 'py310' has python 3.10 -if not exist "%PREFIX%\envs\py310\conda-meta\history" exit 1 -"%PREFIX%\envs\py310\python.exe" -c "from sys import version_info; assert version_info[:2] == (3, 10)" || goto :error +:: extra env named 'py311' has python 3.11 +if not exist "%PREFIX%\envs\py311\conda-meta\history" exit 1 +"%PREFIX%\envs\py311\python.exe" -c "from sys import version_info; assert version_info[:2] == (3, 11)" || goto :error :: extra env named 'dav1d' only contains dav1d, no python if not exist "%PREFIX%\envs\dav1d\conda-meta\history" exit 1 diff --git a/examples/extra_envs/test_install.sh b/examples/extra_envs/test_install.sh index 7cfef8278..a3c84d744 100644 --- a/examples/extra_envs/test_install.sh +++ b/examples/extra_envs/test_install.sh @@ -4,9 +4,9 @@ set -euxo pipefail echo "Added by test-install script" > "$PREFIX/test_install_sentinel.txt" # tests -# base environment uses python 3.9 and excludes tk +# base environment uses python 3.10 and excludes tk test -f "$PREFIX/conda-meta/history" -"$PREFIX/bin/python" -c "from sys import version_info; assert version_info[:2] == (3, 9)" +"$PREFIX/bin/python" -c "from sys import version_info; assert version_info[:2] == (3, 10)" # we use python -m pip instead of the pip entry point # because the spaces break the shebang - this will be fixed # with a new conda release, but for now this is the workaround @@ -16,12 +16,12 @@ test -f "$PREFIX/conda-meta/history" "$PREFIX/bin/python" -m conda list -p "$PREFIX" | jq -e '.[] | select(.name == "tk")' && exit 1 echo "Previous test failed as expected" -# extra env named 'py310' uses python 3.10, has tk, but we removed setuptools -test -f "$PREFIX/envs/py310/conda-meta/history" -"$PREFIX/envs/py310/bin/python" -c "from sys import version_info; assert version_info[:2] == (3, 10)" +# extra env named 'py311' uses python 3.11, has tk, but we removed setuptools +test -f "$PREFIX/envs/py311/conda-meta/history" +"$PREFIX/envs/py311/bin/python" -c "from sys import version_info; assert version_info[:2] == (3, 11)" # setuptools shouldn't be listed by conda! -"$PREFIX/bin/python" -m conda list -p "$PREFIX/envs/py310" | jq -e '.[] | select(.name == "setuptools")' && exit 1 -"$PREFIX/envs/py310/bin/python" -c "import setuptools" && exit 1 +"$PREFIX/bin/python" -m conda list -p "$PREFIX/envs/py311" | jq -e '.[] | select(.name == "setuptools")' && exit 1 +"$PREFIX/envs/py311/bin/python" -c "import setuptools" && exit 1 echo "Previous test failed as expected" # this env only contains dav1d, no python; it should have been created with no errors, diff --git a/examples/from_env_yaml/env.yaml b/examples/from_env_yaml/env.yaml index fc6253531..d919343da 100644 --- a/examples/from_env_yaml/env.yaml +++ b/examples/from_env_yaml/env.yaml @@ -2,5 +2,5 @@ name: testenv channels: - defaults dependencies: - - python=3.9 + - python=3.10 - conda=23.3 diff --git a/examples/from_explicit/explicit_osx-arm64.txt b/examples/from_explicit/explicit_osx-arm64.txt deleted file mode 100644 index 891d899c9..000000000 --- a/examples/from_explicit/explicit_osx-arm64.txt +++ /dev/null @@ -1,19 +0,0 @@ -# This file may be used to create an environment using: -# $ conda create --name --file -# platform: osx-arm64 -@EXPLICIT -https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2021.5.30-h4653dfc_0.tar.bz2#21b35f488f8ccf40c7d3ae05303e24e5 -https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.2-h9aa5885_4.tar.bz2#8a4aa25a5741e65f2338204f8a45d8d8 -https://conda.anaconda.org/conda-forge/noarch/tzdata-2021a-he74cb21_0.tar.bz2#6f36861f102249fc54861ff9343c3fdd -https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.5-h642e427_1.tar.bz2#9ab2316785cb81c464ab9a99512dae71 -https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.2.11-h31e879b_1009.tar.bz2#96796f31644a5e13e12dc194284f7681 -https://conda.anaconda.org/conda-forge/osx-arm64/openssl-1.1.1k-h27ca646_0.tar.bz2#e056be01e85706eeb056d7b979b4a30d -https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.1-hfbdcbf2_0.tar.bz2#c9b0df52c6942e7c7066667fb4ec7404 -https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.10-hf7e6567_1.tar.bz2#42c39bbf010ef4fa5839c61a19535980 -https://conda.anaconda.org/conda-forge/osx-arm64/sqlite-3.35.5-hc49ca36_0.tar.bz2#f7357f92c4a3799f14763cad1d605e64 -https://conda.anaconda.org/conda-forge/osx-arm64/python-3.9.4-h5b20da3_0_cpython.tar.bz2#eee24d5270bca46d9f003f7be5f07de6 -https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.9-1_cp39.tar.bz2#06e5b68ca789e3b7910c3f09cdffda7c -https://conda.anaconda.org/conda-forge/noarch/wheel-0.36.2-pyhd3deb0d_0.tar.bz2#768bfbe026426d0e76b377997d1f2b98 -https://conda.anaconda.org/conda-forge/osx-arm64/certifi-2021.5.30-py39h2804cbe_0.tar.bz2#402804274647d0b524c3de7e46b6162a -https://conda.anaconda.org/conda-forge/osx-arm64/setuptools-49.6.0-py39h2804cbe_3.tar.bz2#b2268b9c73391e6199dc6936da31cddf -https://conda.anaconda.org/conda-forge/noarch/pip-21.1.2-pyhd8ed1ab_0.tar.bz2#dbd830edaffe5fc9ae6c1d425db2b5f2 diff --git a/examples/grin/construct.yaml b/examples/grin/construct.yaml deleted file mode 100644 index 6e3823bc8..000000000 --- a/examples/grin/construct.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# yaml-language-server: $schema=../../constructor/data/construct.schema.json -"$schema": "../../constructor/data/construct.schema.json" - -# name and version (required) -name: test -version: 3 - -# channels to pull packages from -channels: &id1 - - https://repo.anaconda.com/pkgs/main/ - - https://conda.anaconda.org/ilan - -# specifications -specs: - - python - - grin - - sample # [osx] - -# exclude these packages (list of names) -exclude: - - openssl # [unix] - - readline # [unix] - - tk # [unix] - - python - -# explicitly listed packages -# pkgs.txt -packages: - - python-2.7.9-0.tar.bz2 - -keep_pkgs: True - -pre_install: hello.sh # [unix] -post_install: goodbye.sh # [unix] -post_install: test-post.bat # [win] - -# The conda default channels which are used when running a conda which -# was installed be the constructor created (requires conda in the -# specifications) installer -conda_default_channels: *id1 - -# type of the installer being created. Possible values are "sh", "pkg", -# and "exe". By default, the type is "sh" on Unix, and "exe" on Windows. -installer_type: pkg # [osx] - -# installer filename (a reasonable default filename will determined by -# the `name`, (optional) `version`, OS and installer type) -#installer_filename: grin.sh - -# a file with a license text, which is shown during the install process -license_file: eula.txt - -# default install prefix -#default_prefix: /opt/example - -# If `welcome_image` or `header_image` are not provided, their texts -# default to `name`, which may be overridden by the following keys -#welcome_image_text: |- -# multi-line -# welcome-text -#header_image_text: |- -# multi-line -# header-text - -check_path_spaces: False -check_path_length: False diff --git a/examples/grin/eula.txt b/examples/grin/eula.txt deleted file mode 100644 index aa06ac8a7..000000000 --- a/examples/grin/eula.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2016, ... -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of ... nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL ... BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/examples/grin/goodbye.sh b/examples/grin/goodbye.sh deleted file mode 100644 index 1afa24798..000000000 --- a/examples/grin/goodbye.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -euxo pipefail - -echo "Goodbye: PREFIX='$PREFIX'" diff --git a/examples/grin/hello.sh b/examples/grin/hello.sh deleted file mode 100644 index e7c60eb9a..000000000 --- a/examples/grin/hello.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -euxo pipefail - -echo "Hello: PREFIX='$PREFIX'" -echo "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH:-}" diff --git a/examples/grin/pkgs.txt b/examples/grin/pkgs.txt deleted file mode 100644 index 51ad9c750..000000000 --- a/examples/grin/pkgs.txt +++ /dev/null @@ -1,17 +0,0 @@ -# This file may be used to create an environment using: -# $ conda create --name --file -# platform: osx-64 - -#conda=3.17.0=py27_1 - -conda=3.17.0=py27_0 -conda-build=1.17.0=py27_0 - -#https://repo.anaconda.com/pkgs/main/osx-64/openssl-1.0.2o-h26aff7b_0.tar.bz2 -https://repo.anaconda.com/pkgs/main/osx-64/pip-10.0.1-py27_0.tar.bz2 - -pycosat-0.6.1-py27_0.tar.bz2 - -#readline-6.2-2.tar.bz2#0801e644bd0c1cd7f0923b56c52eb7f7 - -https://repo.anaconda.com/pkgs/main/osx-64/yaml-0.1.7-hc338f04_2.tar.bz2#dab654341f57e56b615a678800262b0e diff --git a/examples/grin/test-post.bat b/examples/grin/test-post.bat deleted file mode 100644 index 8a667b30c..000000000 --- a/examples/grin/test-post.bat +++ /dev/null @@ -1 +0,0 @@ -echo "Hello World!" > %PREFIX%\HELLO.txt diff --git a/examples/jetsonconda/EULA.txt b/examples/jetsonconda/EULA.txt deleted file mode 100644 index a31699711..000000000 --- a/examples/jetsonconda/EULA.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2016, Anaconda, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Anaconda, Inc. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL ANACONDA, INC. BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/examples/jetsonconda/README.md b/examples/jetsonconda/README.md deleted file mode 100644 index bf403ae53..000000000 --- a/examples/jetsonconda/README.md +++ /dev/null @@ -1,33 +0,0 @@ -Jetsonconda example -================= - -In this example, we want to demonstrate how to build Jetsonconda installers for -Linux, Mac and Windows. - -We only want to construct installers which include: - - Python 3.5 (because Python 3 is the way of the future) - - `conda`, so people can install additional packages - - `numpy` (but not the MKL linked version, to save space) - - `scipy`, `pandas` - - the Jupyter `notebook` - - `matplotlib` (but not Qt and PyQt, again to save space) - - `lighttpd`, the web server, but only on Unix systems - -We also want to include our license file `EULA.txt`, which located in -this directory. -Also, we want to have a our own welcome image for the Windows installer. -This image `bird.png` is also located in this directory, and is re-sized -by constructor as well. - -Finally, to create a Jetsonconda installer, you simply run (in this directory): - - $ constructor . - ... - $ ls -lh Jetson* - -rwxr-xr-x 1 ilan staff 59M Feb 27 18:02 Jetsonconda-2.5.5-MacOSX-x86_64.sh - -This was done on Mac OS X. -A 60MB installer is not bad for all these packages, I would say. -Note that `constructor` will be default create an installer for the platform -which it is executed on. However, it is also possible to build installers -for other platforms, see the platform key. diff --git a/examples/jetsonconda/bird.png b/examples/jetsonconda/bird.png deleted file mode 100644 index 2efe0f30a..000000000 Binary files a/examples/jetsonconda/bird.png and /dev/null differ diff --git a/examples/jetsonconda/construct.yaml b/examples/jetsonconda/construct.yaml deleted file mode 100644 index ee1b5b49f..000000000 --- a/examples/jetsonconda/construct.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# yaml-language-server: $schema=../../constructor/data/construct.schema.json -"$schema": "../../constructor/data/construct.schema.json" - -name: JetsonConda -version: 0.1 - -channels: - - https://conda.anaconda.org/aarch64_gbox - -specs: - - python 3.6* - - conda # [aarch64] - - numpy # [aarch64] - - scipy # [aarch64] - - pandas # [aarch64] - - notebook # [aarch64] - - matplotlib # [aarch64] - - freetype # [aarch64] - -#license_file: EULA.txt - -# Welcome image for Windows installer -welcome_image: bird.png # [win] diff --git a/examples/miniconda/EULA.txt b/examples/miniconda/EULA.txt deleted file mode 100644 index a31699711..000000000 --- a/examples/miniconda/EULA.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2016, Anaconda, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Anaconda, Inc. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL ANACONDA, INC. BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/examples/miniconda/README.md b/examples/miniconda/README.md deleted file mode 100644 index 86087cf73..000000000 --- a/examples/miniconda/README.md +++ /dev/null @@ -1,34 +0,0 @@ -Miniconda example -================= - -In this example, we want to demonstrate how to build installers for -Linux, Mac and Windows, which are similar to Anaconda installers, but -significantly smaller in size. - -We only want to construct installers which include: - - Python 3.5 (because Python 3 is the way of the future) - - `conda`, so people can install additional packages - - `numpy` (but not the MKL linked version, to save space) - - `scipy`, `pandas` - - the Jupyter `notebook` - - `matplotlib` (but not Qt and PyQt, again to save space) - - `lighttpd`, the web server, but only on Unix systems - -We also want to include our license file `EULA.txt`, which located in -this directory. -Also, we want to have a our own welcome image for the Windows installer. -This image `bird.png` is also located in this directory, and is re-sized -by constructor as well. - -Finally, to create a Miniconda installer, you simply run (in this directory): - - $ constructor . - ... - $ ls -lh Mini* - -rwxr-xr-x 1 ilan staff 59M Feb 27 18:02 Miniconda-2.5.5-MacOSX-x86_64.sh - -This was done on Mac OS X. -A 60MB installer is not bad for all these packages, I would say. -Note that `constructor` will be default create an installer for the platform -which it is executed on. However, it is also possible to build installers -for other platforms, see the platform key. diff --git a/examples/miniconda/construct.yaml b/examples/miniconda/construct.yaml deleted file mode 100644 index 589b4223a..000000000 --- a/examples/miniconda/construct.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# yaml-language-server: $schema=../../constructor/data/construct.schema.json -"$schema": "../../constructor/data/construct.schema.json" - -name: MinicondaX -version: X -installer_type: all - -channels: - - https://repo.anaconda.com/pkgs/main/ - -specs: - - python - - conda diff --git a/examples/newchan/construct.yaml b/examples/newchan/construct.yaml deleted file mode 100644 index 147d94424..000000000 --- a/examples/newchan/construct.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# yaml-language-server: $schema=../../constructor/data/construct.schema.json -"$schema": "../../constructor/data/construct.schema.json" - -name: Funnychan -version: 2.5.5 - -channels: - - https://repo.anaconda.com/pkgs/main/ - - https://conda.anaconda.org/ilan - -# specifications -specs: - - python - - grin - - sample - -license_file: eula.txt - -check_path_spaces: False -check_path_length: False diff --git a/examples/newchan/eula.txt b/examples/newchan/eula.txt deleted file mode 100644 index aa06ac8a7..000000000 --- a/examples/newchan/eula.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2016, ... -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of ... nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL ... BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/news/1145-python-test-deps b/news/1145-python-test-deps new file mode 100644 index 000000000..f3179bf63 --- /dev/null +++ b/news/1145-python-test-deps @@ -0,0 +1,19 @@ +### Enhancements + +* + +### Bug fixes + +* + +### Deprecations + +* + +### Docs + +* + +### Other + +* Remove Python `3.9` from the testing suite, include Python `3.13`. (#1145) diff --git a/pyproject.toml b/pyproject.toml index 8f48009ac..f54eaac55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "constructor" description = "create installer from conda packages" readme = "README.md" license = {text = "BSD-3-Clause"} -requires-python = ">=3.8" +requires-python = ">=3.10" dynamic = [ "version", ] @@ -46,7 +46,7 @@ constructor = [ [tool.ruff] line-length = 100 -target-version = "py39" +target-version = "py310" exclude = [ "constructor/nsis/*.py", ] diff --git a/recipe/meta.yaml b/recipe/meta.yaml index f9334ccb7..d68af36a1 100644 --- a/recipe/meta.yaml +++ b/recipe/meta.yaml @@ -17,13 +17,13 @@ build: requirements: host: - - python # >=3.8 + - python # >=3.10 - pip - setuptools >=70.1 - setuptools_scm >=6.2 run: - conda >=4.6 - - python # >=3.8 + - python # >=3.10 - ruamel.yaml >=0.11.14,<0.19 - conda-standalone >=24.1.2 - jinja2 diff --git a/scripts/run_examples.py b/scripts/run_examples.py deleted file mode 100644 index eea2c63b3..000000000 --- a/scripts/run_examples.py +++ /dev/null @@ -1,340 +0,0 @@ -#!/usr/bin/env python -"""Run examples bundled with this repo.""" - -import argparse -import os -import platform -import shutil -import subprocess -import sys -import tempfile -import time -import warnings -from datetime import timedelta -from pathlib import Path - -from constructor.utils import rm_rf - -try: - import coverage # noqa - - COV_CMD = ["coverage", "run", "--branch", "--append", "-m"] -except ImportError: - COV_CMD = [] - - -warnings.warn( - "This script is now deprecated and will be removed soon. " - "Please use tests/test_examples.py with pytest.", - DeprecationWarning, -) - - -HERE = os.path.abspath(os.path.dirname(__file__)) -REPO_DIR = os.path.dirname(HERE) -EXAMPLES_DIR = os.path.join(REPO_DIR, "examples") -PY3 = sys.version_info[0] == 3 -WHITELIST = ["grin", "jetsonconda", "miniconda", "newchan"] -BLACKLIST = [] -WITH_SPACES = {"extra_files", "noconda", "signing", "scripts"} - -# .sh installers to also test in interactiv mode -# (require all to a have License = have same interactive input steps) -INTERACTIVE_TESTS = ["miniforge"] -# Test runs with even Python version are done in interactive mode, odd in batch mode -INTERACTIVE_TESTING = (sys.version_info.minor % 2) == 0 - - -def _execute(cmd, installer_input=None, **env_vars): - print(" ".join(cmd)) - t0 = time.time() - if env_vars: - env = os.environ.copy() - env.update(env_vars) - else: - env = None - p = subprocess.Popen( - cmd, - stdin=subprocess.PIPE if installer_input else None, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - stdout, stderr = p.communicate(input=installer_input, timeout=420) - errored = p.returncode != 0 - except subprocess.TimeoutExpired: - p.kill() - stdout, stderr = p.communicate() - print("--- TEST TIMEOUT ---") - errored = True - t1 = time.time() - if errored or "CONDA_VERBOSITY" in env_vars: - print(f"--- RETURNCODE: {p.returncode} ---") - if stdout: - print("--- STDOUT ---") - print(stdout) - if stderr: - print("--- STDERR ---") - print(stderr) - print("--- Done in", timedelta(seconds=t1 - t0)) - return errored - - -def run_examples(keep_artifacts=None, conda_exe=None, debug=False): - """Run examples bundled with the repository. - - Parameters - ---------- - keep_artifacts: str, optional=None - Path where the generated installers will be moved to. - Will be created if it doesn't exist. - - Returns - ------- - int - Number of failed examples - """ - if sys.platform.startswith("win") and "NSIS_USING_LOG_BUILD" not in os.environ: - print( - "! Warning !" - " Windows installers are tested with NSIS in silent mode, which does" - " not report errors on exit. You should use logging-enabled NSIS builds" - " to generate an 'install.log' file this script will search for errors" - " after completion." - ) - example_paths = [] - errored = 0 - if platform.system() != "Darwin": - BLACKLIST.append(os.path.join(EXAMPLES_DIR, "osxpkg")) - if keep_artifacts: - os.makedirs(keep_artifacts, exist_ok=True) - - whitelist = [os.path.join(EXAMPLES_DIR, p) for p in WHITELIST] - for fname in os.listdir(EXAMPLES_DIR): - fpath = os.path.join(EXAMPLES_DIR, fname) - if os.path.isdir(fpath) and fpath not in whitelist and fpath not in BLACKLIST: - if os.path.exists(os.path.join(fpath, "construct.yaml")): - example_paths.append(fpath) - - parent_output = tempfile.mkdtemp() - tested_files = set() - which_errored = {} - for example_path in sorted(example_paths): - example_name = Path(example_path).name - test_with_spaces = example_name in WITH_SPACES - print(example_name) - print("-" * len(example_name)) - if ( - sys.platform.startswith("win") - and conda_exe - and "micromamba" in os.path.basename(conda_exe).lower() - ): - print( - f"! Skipping {example_name}... Shortcut creation on Windows is " - "not supported with micromamba." - ) - continue - output_dir = tempfile.mkdtemp(prefix=f"{example_name}-", dir=parent_output) - # resolve path to avoid some issues with TEMPDIR on Windows - output_dir = str(Path(output_dir).resolve()) - is_fromenv = os.path.basename(example_path) == "fromenv" - if is_fromenv: - env_file = os.path.join(example_path, "environment.txt") - test_prefix = os.path.join(example_path, "tmp_prefix_fromenv") - cmd = ["conda", "create", "--prefix", test_prefix, "--file", env_file, "--yes"] - errored += _execute(cmd) - cmd = COV_CMD + ["constructor", "-v", example_path, "--output-dir", output_dir] - if conda_exe: - cmd += ["--conda-exe", conda_exe] - if debug: - cmd.append("--debug") - creation_errored = _execute(cmd) - if is_fromenv: - rm_rf(test_prefix) - errored += creation_errored - for fpath in os.listdir(output_dir): - ext = fpath.rsplit(".", 1)[-1] - if fpath in tested_files or ext not in ("sh", "exe", "pkg"): - continue - tested_files.add(fpath) - test_suffix = "s p a c e s" if test_with_spaces else None - env_dir = tempfile.mkdtemp(suffix=test_suffix, dir=output_dir) - rm_rf(env_dir) - fpath = os.path.join(output_dir, fpath) - print("--- Testing", os.path.basename(fpath)) - installer_input = None - if ext == "sh": - if INTERACTIVE_TESTING and example_name in INTERACTIVE_TESTS: - cmd = ["/bin/sh", fpath] - # Input: Enter, yes to the license, installation folder, no to initialize shells - installer_input = f"\nyes\n{env_dir}\nno\n" - else: - cmd = ["/bin/sh", fpath, "-b", "-p", env_dir] - elif ext == "pkg": - if os.environ.get("CI"): - # We want to run it in an arbitrary directory, but the options - # are limited here... We can only install to $HOME :shrug: - # but that will pollute ~, so we only do it if we are running on CI - cmd = [ - "installer", - "-pkg", - fpath, - "-dumplog", - "-target", - "CurrentUserHomeDirectory", - ] - else: - # This command only expands the PKG, but does not install - cmd = ["pkgutil", "--expand", fpath, env_dir] - elif ext == "exe": - # NSIS manual: - # > /D sets the default installation directory ($INSTDIR), overriding InstallDir - # > and InstallDirRegKey. It must be the last parameter used in the command line - # > and must not contain any quotes, even if the path contains spaces. Only - # > absolute paths are supported. - # Since subprocess.Popen WILL escape the spaces with quotes, we need to provide - # them as separate arguments. We don't care about multiple spaces collapsing into - # one, since the point is to just have spaces in the installation path -- one - # would be enough too :) - # This is why we have this weird .split() thingy down here: - cmd = ["cmd.exe", "/c", "start", "/wait", fpath, "/S", *f"/D={env_dir}".split()] - env = {"CONDA_VERBOSITY": "3"} if debug else {} - test_errored = _execute(cmd, installer_input=installer_input, **env) - # Windows EXEs never throw a non-0 exit code, so we need to check the logs, - # which are only written if a special NSIS build is used - win_error_lines = [] - if ext == "exe" and os.environ.get("NSIS_USING_LOG_BUILD"): - test_errored = 0 - try: - log_is_empty = True - with open(os.path.join(env_dir, "install.log"), encoding="utf-16-le") as f: - for line in f: - log_is_empty = False - if ":error:" in line.lower(): - win_error_lines.append(line) - test_errored = 1 - if log_is_empty: - test_errored = 1 - win_error_lines.append("Logfile was unexpectedly empty!") - except Exception as exc: - test_errored = 1 - win_error_lines.append( - f"Could not read logs! {exc.__class__.__name__}: {exc}\n" - "This usually means that the destination folder could not be created.\n" - "Possible causes: permissions, non-supported characters, long paths...\n" - "Consider setting 'check_path_spaces' and 'check_path_length' to 'False'." - ) - for script_prefix in "pre", "post", "test": - install_location = Path(env_dir) - if ext == "exe": - script_ext = "bat" - elif ext == "sh": - script_ext = "sh" - elif example_name == "osxpkg": # we only test one pkg example - script_ext = "sh" - install_location = Path("~/Library/osx-pkg-test").expanduser() - else: - continue - if (Path(example_path) / f"{script_prefix}_install.{script_ext}").exists() and not ( - install_location / f"{script_prefix}_install_sentinel.txt" - ).exists(): - # All pre/post scripts need to write a sentinel file so we can tell they did run - test_errored += 1 - which_errored.setdefault(example_path, []).append( - f"Did not find {script_prefix}_install.{script_ext} sentinel!" - ) - errored += test_errored - if test_errored: - which_errored.setdefault(example_path, []).append(fpath) - if win_error_lines: - print("--- LOGS ---") - for line in win_error_lines: - print(line.rstrip()) - if ext == "pkg" and os.environ.get("CI"): - # more complete logs are available under /var/log/install.log - print("--- LOGS ---") - print("Tip: Debug locally and check the full logs in the Installer UI") - print(" or check /var/log/install.log if run from the CLI.") - elif ext == "exe" and not test_with_spaces: - # The installer succeeded, test the uninstaller on Windows - # The un-installers are only tested when testing without spaces, as they hang during - # testing but work in UI mode. - uninstaller = next( - (p for p in os.listdir(env_dir) if p.startswith("Uninstall-")), None - ) - if uninstaller: - cmd = [ - "cmd.exe", - "/c", - "start", - "/wait", - os.path.join(env_dir, uninstaller), - # We need silent mode + "uninstaller location" (_?=...) so the command can - # be waited; otherwise, since the uninstaller copies itself to a different - # location so it can be auto-deleted, it returns immediately and it gives - # us problems with the tempdir cleanup later - f"/S _?={env_dir}", - ] - test_errored = _execute(cmd) - errored += test_errored - if test_errored: - which_errored.setdefault(example_path, []).append( - "Wrong uninstall exit code or timeout." - ) - paths_after_uninstall = os.listdir(env_dir) - if len(paths_after_uninstall) > 2: - # The debug installer writes to install.log too, which will only - # be deleted _after_ a reboot. Finding some files is ok, but more - # than two usually means a problem with the uninstaller. - # Note this is is not exhaustive, because we are not checking - # whether the registry was restored, menu items were deleted, etc. - # TODO :) - which_errored.setdefault(example_path, []).append( - "Uninstaller left too many files behind!\n - \n - ".join( - paths_after_uninstall - ) - ) - else: - which_errored.setdefault(example_path, []).append("Could not find uninstaller!") - - if keep_artifacts: - dest = os.path.join(keep_artifacts, os.path.basename(fpath)) - if os.path.isfile(dest): - os.unlink(dest) - shutil.move(fpath, keep_artifacts) - if creation_errored: - which_errored.setdefault(example_path, []).append("Could not create installer!") - print() - - print("-------------------------------") - if errored: - print("Some examples failed:") - for installer, reasons in which_errored.items(): - print(f"+ {os.path.basename(installer)}") - for reason in reasons: - print(f"---> {reason}") - print("Assets saved in:", keep_artifacts or parent_output) - else: - print("All examples ran successfully!") - shutil.rmtree(parent_output) - return errored - - -def cli(): - p = argparse.ArgumentParser() - p.add_argument("--keep-artifacts") - p.add_argument("--conda-exe") - p.add_argument("--debug", action="store_true", default=False) - return p.parse_args() - - -if __name__ == "__main__": - args = cli() - if args.conda_exe: - assert os.path.isfile(args.conda_exe) - n_errors = run_examples( - keep_artifacts=args.keep_artifacts, conda_exe=args.conda_exe, debug=args.debug - ) - sys.exit(n_errors)