diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b74dc043..32314e15 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -86,11 +86,11 @@ jobs: include: # include the appropriate dependencies for testing SquashFS on each OS - os: macos-12 - squashfs_deps: "conda-forge::squashfs-tools" + conda_deps: "conda-forge::squashfs-tools conda-forge::fish" - os: ubuntu-latest - squashfs_deps: "conda-forge::squashfs-tools conda-forge::squashfuse" + conda_deps: "conda-forge::squashfs-tools conda-forge::squashfuse conda-forge::fish" - os: windows-latest - squashfs_deps: "" + conda_deps: "" steps: - name: Retrieve the source code uses: actions/checkout@v4 @@ -118,7 +118,7 @@ jobs: source $CONDA_ROOT/etc/profile.d/conda.sh conda info -a mv conda-bld $CONDA_ROOT/conda-bld - conda create -n cptest local::conda-pack conda-forge::pytest conda-forge::pytest-cov defaults::python=${{ matrix.pyver }} ${{ matrix.squashfs_deps }} + conda create -n cptest local::conda-pack conda-forge::pytest conda-forge::pytest-cov defaults::python=${{ matrix.pyver }} ${{ matrix.conda_deps }} conda activate cptest pytest -v -ss --cov=conda_pack --cov-branch --cov-report=xml conda_pack/tests - uses: codecov/codecov-action@v4 diff --git a/conda_pack/core.py b/conda_pack/core.py index 19196991..33a1dca8 100644 --- a/conda_pack/core.py +++ b/conda_pack/core.py @@ -42,7 +42,9 @@ class CondaPackException(Exception): _scripts = [(os.path.join(_current_dir, 'scripts', 'posix', 'activate'), os.path.join(BIN_DIR, 'activate')), (os.path.join(_current_dir, 'scripts', 'posix', 'deactivate'), - os.path.join(BIN_DIR, 'deactivate'))] + os.path.join(BIN_DIR, 'deactivate')), + (os.path.join(_current_dir, 'scripts', 'posix', 'activate.fish'), + os.path.join(BIN_DIR, 'activate.fish'))] class _Context: diff --git a/conda_pack/scripts/posix/activate.fish b/conda_pack/scripts/posix/activate.fish new file mode 100644 index 00000000..742a0c79 --- /dev/null +++ b/conda_pack/scripts/posix/activate.fish @@ -0,0 +1,62 @@ +function _activate + set -l full_path_script_dir (cd (dirname (status -f)); and pwd) + set -l full_path_env (dirname "$full_path_script_dir") + set env_name (basename "$full_path_env") + + # If there's already a source env + if [ -n "$CONDA_PREFIX" ] + # If the source env differs from this env + if [ "$CONDA_PREFIX" != "$full_path_env" ] + deactivate + else + return 0 # nothing to do + end + end + + export CONDA_PREFIX="$full_path_env" + set _OLD_PATH "$PATH" + set PATH "$full_path_env/bin:$PATH" + + functions -c fish_prompt _old_fish_prompt + function fish_prompt + # Run the user's prompt first; it might depend on (pipe)status. + set -l prompt (_old_fish_prompt) + + printf "($env_name) " + + string join -- \n $prompt # handle multi-line prompts + end + + # Run the activate scripts + set -l _script_dir "$full_path_env/etc/conda/activate.d" + if [ -d "$_script_dir" ] && [ -n "(ls -A "$_script_dir")" ] + set -l _path + for _path in "$_script_dir"/*.sh + # Normally these are sourced but given they're not-fish scripts it will + # error out. Run them anyways for any side effects. + sh "$_path" + end + for _path in "$_script_dir"/*.fish + . "$_path" + end + end +end + +function deactivate -d 'Exit conda mode and return to the normal environment.' + # reset old environment variables + if test -n "$_OLD_PATH" + set -gx PATH $_OLD_PATH + set -e _OLD_PATH + end + + if functions -q _old_fish_prompt + # Erase virtualenv's `fish_prompt` and restore the original. + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + + set -e CONDA_PREFIX +end + +_activate diff --git a/conda_pack/tests/test_core.py b/conda_pack/tests/test_core.py index 355185f7..0625786c 100644 --- a/conda_pack/tests/test_core.py +++ b/conda_pack/tests/test_core.py @@ -509,7 +509,7 @@ def test_pack(tmpdir, py37_env): fnames = ('conda-unpack.exe', 'conda-unpack-script.py', 'activate.bat', 'deactivate.bat') else: - fnames = ('conda-unpack', 'activate', 'deactivate') + fnames = ('conda-unpack', 'activate', 'deactivate', 'activate.fish') assert diff == {os.path.join(BIN_DIR_L, f) for f in fnames} @@ -622,6 +622,7 @@ def test_activate(tmpdir): assert out == 'CONDAPACK_ACTIVATED=1\r\nCONDAPACK_ACTIVATED=\r\nDone\r\n' else: + # bash command = (". {path}/bin/activate && " "test $CONDAPACK_ACTIVATED -eq 1 && " ". {path}/bin/deactivate && " @@ -632,3 +633,14 @@ def test_activate(tmpdir): stderr=subprocess.STDOUT).decode() assert out == 'Done\n' + + # fish + command = (". {path}/bin/activate.fish && " + "python -c 'import sys; print(sys.executable)' && " + "deactivate && " + "echo 'Done'").format(path=extract_path) + + out = subprocess.check_output(['/usr/bin/env', 'fish', '-c', command], + stderr=subprocess.STDOUT).decode() + assert "test_activate0" in out + assert "Done\n" in out