diff --git a/README.md b/README.md index 99c3802..f46b8f0 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,7 @@ on the sqfs image itself. This behavior can be disabled by setting `CW_NO_FIX_PE - `pip-containerize` - Wrap new venv installation or edit existing - Will by default use currently available python + - Option to use uv to manage python and venv - Option to also use slim container image (will then not mount full host) - `wrap-container` - Generate wrappers for existing container. Mainly diff --git a/frontends/conda-containerize.py b/frontends/conda-containerize.py index b74e29b..032d627 100644 --- a/frontends/conda-containerize.py +++ b/frontends/conda-containerize.py @@ -17,8 +17,17 @@ parser_new=add_new_pars(subparsers) parser_new.add_argument("env_file",help="conda env file") parser_new.add_argument("--mamba",help="use mamba for installation",action="store_true") +parser_new.add_argument( + "--uv", help="use uv for pip dependencies (only with mamba)", action="store_true" +) +parser_new.add_argument( + "--nocache", help="Do not use pip/uv cache", action="store_true" +) parser_upd=add_upd_pars(subparsers) add_adv_pars(subparsers) +parser_upd.add_argument( + "--nocache", help="Do not use pip/uv cache", action="store_true" +) ps=[parser_new,parser_upd] for p in ps: @@ -31,8 +40,13 @@ args = parser.parse_args() conf={} conf["add_ld"]="no" +conf["use_uv"] = "no" +conf["mode"] = "conda" +conf["template_script"] = "conda.sh" if args.command == "new": conf["env_file"]=args.env_file + conf["update_installation"] = "no" + conf["installation_file_paths"] = [conf["env_file"]] if args.prefix: conf["installation_prefix"]=args.prefix conf["mode"]="conda" @@ -40,8 +54,12 @@ conf["mamba"]="yes" else: conf["mamba"]="no" + if args.uv and args.mamba: + conf["use_uv"] = "yes" + elif args.uv and not args.mamba: + print_warn("Using --uv without --mamba does not have an effect") elif args.command == "update": - conf["mode"]="conda_modify" + conf["update_installation"] = "yes" get_old_conf(args.dir,conf) else: with open(args.yaml,'r') as y: @@ -69,22 +87,18 @@ global_conf=yaml.safe_load(g) parse_wrapper(conf,global_conf,args,False) -if conf["mode"] == "conda": - conf["update_installation"]="no" - conf["template_script"]="conda.sh" - conf["installation_file_paths"]=[conf["env_file"]] -elif conf["mode"]=="conda_modify": - conf["update_installation"]="yes" - conf["template_script"]="conda_modify.sh" -else: - print_err("No or incorrent mode set, [conda,conda_modify]") - sys.exit(1) + if "requirements_file" in conf: if "installation_file_paths" in conf: conf["installation_file_paths"].append(conf["requirements_file"]) else: conf["installation_file_paths"]=conf["requirements_file"] +if "pipcache" not in conf: + conf["pipcache"] = True + +if args.nocache is not None: + conf["pipcache"] = not args.nocache with open(os.getenv("_usr_yaml"),'a+') as f: yaml.dump(conf,f) diff --git a/frontends/pip-containerize.py b/frontends/pip-containerize.py index 7aaa9a9..fb060ce 100644 --- a/frontends/pip-containerize.py +++ b/frontends/pip-containerize.py @@ -18,48 +18,60 @@ parser_new.add_argument("requirements_file", type=lambda x: is_valid_file(parser, x),help="requirements file for pip") parser_upd=add_upd_pars(subparsers) parser_upd.add_argument("-r","--requirements-file", type=lambda x: is_valid_file(parser, x),help="requirements file for pip") +parser_upd.add_argument( + "--nocache", help="Do not use pip/uv cache", action="store_true" +) add_adv_pars(subparsers) -parser_new.add_argument("--slim",action='store_true',help="Use minimal base python container") -parser_new.add_argument("--pyver",help="Docker tag to use for the slim python verison, e.g 3.12.9-bookworm") +python_mode = parser_new.add_mutually_exclusive_group() +python_mode.add_argument("--uv", action="store_true", help="Use uv") +python_mode.add_argument( + "--slim", action="store_true", help="Use minimal base python container" +) +parser_new.add_argument("--pyver", help="Python version to use for slim or uv modes") parser_new.add_argument("--system-site-packages",action='store_true',help="Enable system and user site packages for the created installation") +parser_new.add_argument("--nocache", help="Do not use pip/uv cache", action="store_true") ps=[parser_new,parser_upd] for p in ps: add_base_pars(p) - - - if len(sys.argv) < 2: parser.print_help() sys.exit(0) args = parser.parse_args() -conf={} -pyver="3.12.9-slim-bookworm" - - +conf = {} if args.requirements_file: conf["requirements_file"]=args.requirements_file conf["installation_file_paths"]=[conf["requirements_file"]] if args.command == "new": + conf["mode"] = "venv" + conf["use_uv"] = "no" + conf["update_installation"] = "no" if args.system_site_packages: conf["enable_site_packages"]="yes" if args.prefix: conf["installation_prefix"]=args.prefix - conf["mode"]="venv" if args.slim: + conf["pyver"] = "slim" if args.pyver: - pyver=args.pyver - conf["container_src"]="docker://python:{}".format(pyver) - conf["isolate"]="yes" + if "-slim" in args.pyver or args.pyver == "slim": + conf["pyver"] = args.pyver + else: + conf["pyver"] = args.pyver + "-slim" + + conf["container_src"] = "docker://python:{}".format(conf["pyver"]) + conf["isolate"] = "yes" + elif args.uv: + conf["use_uv"] = "yes" + conf["pyver"] = args.pyver if args.pyver else "3" else: if args.pyver: - print_warn("Using --pyver without --slim does not have an effect") + print_warn("Using --pyver without --slim or --uv does not have an effect") elif args.command == "update": - conf["mode"]="venv_modify" + conf["update_installation"] = "yes" get_old_conf(args.dir,conf) else: with open(args.yaml,'r') as y: @@ -81,12 +93,14 @@ global_conf=yaml.safe_load(g) parse_wrapper(conf,global_conf,args,False) -if conf["mode"] == "venv": - conf["update_installation"]="no" - conf["template_script"]="venv.sh" -else: - conf["update_installation"]="yes" - conf["template_script"]="venv_modify.sh" + +conf["template_script"] = "venv.sh" + +if "pipcache" not in conf: + conf["pipcache"] = True + +if args.nocache is not None: + conf["pipcache"] = not args.nocache with open(os.getenv("_usr_yaml"),'a+') as f: yaml.dump(conf,f) diff --git a/frontends/script_shared.py b/frontends/script_shared.py index f906db8..f993396 100644 --- a/frontends/script_shared.py +++ b/frontends/script_shared.py @@ -93,5 +93,12 @@ def get_old_conf(d,conf): conf["sqfs_image"]=old_conf["sqfs_image"] conf["container_image"]=old_conf["container_image"] conf["isolate"]=old_conf["isolate"] + conf["mode"] = old_conf["mode"] + if "mamba" in old_conf: + conf["mamba"] = old_conf["mamba"] + if "use_uv" in old_conf: + conf["use_uv"] = old_conf["use_uv"] + if "pipcache" in old_conf: + conf["pipcache"] = old_conf["pipcache"] if "wrapper_paths" in old_conf: conf["wrapper_paths"] = old_conf["wrapper_paths"] diff --git a/generate_wrappers.sh b/generate_wrappers.sh index 6fb0a7d..63e1f27 100755 --- a/generate_wrappers.sh +++ b/generate_wrappers.sh @@ -242,7 +242,7 @@ fi" >> _deploy/bin/$target if [[ ! -z "$($_CONTAINER_EXEC ls $wrapper_path/../pyvenv.cfg 2>/dev/null )" ]]; then print_info "Target is a venv" 2 $_CONTAINER_EXEC cat $wrapper_path/../pyvenv.cfg > _deploy/pyvenv.cfg - _pyd=$($_CONTAINER_EXEC ls $wrapper_path/../lib) + _pyd=$(basename "$($_CONTAINER_EXEC find $wrapper_path/../lib -maxdepth 1 -type d -regex '.*/python[0-9]+\.[0-9]+$')") mkdir -p _deploy/lib/$_pyd/ (cd _deploy/lib/$_pyd && ln -s $wrapper_path/../lib/$_pyd/site-packages site-packages ) (cd _deploy && ln -s lib lib64 ) diff --git a/templates/conda.sh b/templates/conda.sh index e6eb2a6..8774f0c 100644 --- a/templates/conda.sh +++ b/templates/conda.sh @@ -9,17 +9,25 @@ export env_root=$CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/ cd $CW_INSTALLATION_PATH -[ "$CW_CONDA_VERSION" = "latest" ] && CW_CONDA_VERSION=$(curl -s https://api.github.com/repos/conda-forge/miniforge/releases/latest | grep "tag_name" | cut -d: -f2 | tr -d \" | tr -d , | tr -d " ") +if [[ ! -e $CW_INSTALLATION_PATH/miniforge/ ]]; then + if [[ -e $CW_INSTALLATION_PATH/miniconda/ ]]; then + print_info "Updating older installation which is using miniconda and not miniforge\nCreating symlink miniforge -> miniconda" 1 + ln -s "$CW_INSTALLATION_PATH/miniconda" "$CW_INSTALLATION_PATH/miniforge" + else + [ "$CW_CONDA_VERSION" = "latest" ] && CW_CONDA_VERSION=$(curl -s https://api.github.com/repos/conda-forge/miniforge/releases/latest | grep "tag_name" | cut -d: -f2 | tr -d \" | tr -d , | tr -d " ") -print_info "Using miniforge version Miniforge3-$CW_CONDA_VERSION-$CW_CONDA_ARCH" 1 -print_info "Downloading miniforge " 2 -curl -sL https://github.com/conda-forge/miniforge/releases/download/$CW_CONDA_VERSION/Miniforge3-$CW_CONDA_VERSION-$CW_CONDA_ARCH.sh --output Miniforge_inst.sh &>/dev/null -print_info "Installing miniforge " 1 -bash Miniforge_inst.sh -b -p $CW_INSTALLATION_PATH/miniforge > $CW_BUILD_TMPDIR/_inst_miniforge.log & -inst_pid=$! + print_info "Using miniforge version Miniforge3-$CW_CONDA_VERSION-$CW_CONDA_ARCH" 1 + print_info "Downloading miniforge " 2 + curl -sL "https://github.com/conda-forge/miniforge/releases/download/$CW_CONDA_VERSION/Miniforge3-$CW_CONDA_VERSION-$CW_CONDA_ARCH.sh" --output Miniforge_inst.sh &>/dev/null + print_info "Installing miniforge " 1 + bash Miniforge_inst.sh -b -p "$CW_INSTALLATION_PATH/miniforge" > "$CW_BUILD_TMPDIR/_inst_miniforge.log" & + inst_pid=$! + + follow_log $inst_pid "$CW_BUILD_TMPDIR/_inst_miniforge.log" 20 + rm Miniforge_inst.sh + fi +fi -follow_log $inst_pid $CW_BUILD_TMPDIR/_inst_miniforge.log 20 -rm Miniforge_inst.sh eval "$($CW_INSTALLATION_PATH/miniforge/bin/conda shell.bash hook)" cd $CW_WORKDIR @@ -31,21 +39,44 @@ else _FF="--file" fi cd $CW_INSTALLATION_PATH -print_info "Creating env, full log in $CW_BUILD_TMPDIR/build.log" 1 -if [[ ${CW_MAMBA} == "yes" ]] ;then - print_info "Using mamba to install packages" 1 - mamba $_EC create --name $CW_ENV_NAME $_FF $( basename $CW_ENV_FILE ) &>> $CW_BUILD_TMPDIR/build.log & -else - conda $_EC create --name $CW_ENV_NAME $_FF $( basename $CW_ENV_FILE ) &>> $CW_BUILD_TMPDIR/build.log & +if [[ "$CW_PIPCACHE" != "yes" ]]; then + export PIP_NO_CACHE_DIR=1 + export UV_NO_CACHE=1 +fi + +_UV="" +if [[ ${CW_USE_UV} == "yes" ]] ; then + export UV_LINK_MODE=copy + _UV="--use-uv" fi -inst_pid=$! -follow_log $inst_pid $CW_BUILD_TMPDIR/build.log 20 -wait $inst_pid -conda activate $CW_ENV_NAME +if [[ ! -e "$env_root" ]]; then + print_info "Creating env, full log in $CW_BUILD_TMPDIR/build.log" 1 + + if [[ ${CW_MAMBA} == "yes" ]] ; then + print_info "Using mamba to install packages" 1 + mamba $_EC create -y $_UV --name "$CW_ENV_NAME" $_FF "$( basename "$CW_ENV_FILE" )" &>> "$CW_BUILD_TMPDIR/build.log" & + else + conda $_EC create -y --name "$CW_ENV_NAME" $_FF "$( basename "$CW_ENV_FILE" )" &>> "$CW_BUILD_TMPDIR/build.log" & + fi + inst_pid=$! + follow_log $inst_pid "$CW_BUILD_TMPDIR/build.log" 20 + wait $inst_pid +fi + +conda activate "$CW_ENV_NAME" + if [[ ${CW_REQUIREMENTS_FILE+defined} ]];then - pip install -r $( basename "$CW_REQUIREMENTS_FILE" ) + print_info "Installing requirements file" 1 + if [[ ${CW_USE_UV} == "yes" ]] ; then + uv pip install -r "$( basename "$CW_REQUIREMENTS_FILE" )" > "$CW_BUILD_TMPDIR/_pip.log" & + else + pip install -r "$( basename "$CW_REQUIREMENTS_FILE" )"> "$CW_BUILD_TMPDIR/_pip.log" & + fi + bg_pid=$! + wait $bg_pid + follow_log $bg_pid "$CW_BUILD_TMPDIR/_pip.log" 20 fi cd $CW_WORKDIR print_info "Running user supplied commands" 1 diff --git a/templates/conda_modify.sh b/templates/conda_modify.sh deleted file mode 100644 index 0283a6f..0000000 --- a/templates/conda_modify.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - - -## Fix for updating older installations - -if [[ ! -e $CW_INSTALLATION_PATH/miniforge/ ]];then - print_info "Updating older installation which is using miniconda and not miniforge\nCreating symlink miniforge -> miniconda" 1 - ln -s "$CW_INSTALLATION_PATH/miniconda" "$CW_INSTALLATION_PATH/miniforge" -fi - -cd $CW_BUILD_TMPDIR -echo "export env_root=$CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/" >> _extra_envs.sh -echo "export env_root=$CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/" >> _vars.sh -cd $CW_INSTALLATION_PATH -export env_root=$CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/ -eval "$($CW_INSTALLATION_PATH/miniforge/bin/conda shell.bash hook)" -cd $CW_WORKDIR -source $CW_INSTALLATION_PATH/_pre_install.sh -conda activate $CW_ENV_NAME -if [[ ${CW_REQUIREMENTS_FILE+defined} ]];then - print_info "Installing requirements file" 1 - pip install -r $( basename "$CW_REQUIREMENTS_FILE" ) > $CW_BUILD_TMPDIR/_pip.log & - bg_pid=$! - wait $bg_pid - follow_log $bg_pid $CW_BUILD_TMPDIR/_pip.log 20 -fi -cd $CW_WORKDIR -source $CW_INSTALLATION_PATH/_post_install.sh -echo 'echo "' > $CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/bin/list-packages -conda list >> $CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/bin/list-packages -echo '"' >> $CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/bin/list-packages -chmod +x $CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/bin/list-packages - -echo "CW_WRAPPER_PATHS+=( \"$CW_INSTALLATION_PATH/miniforge/envs/$CW_ENV_NAME/bin/\" )" >> $CW_BUILD_TMPDIR/_vars.sh diff --git a/templates/venv.sh b/templates/venv.sh index 03816f9..19ed478 100644 --- a/templates/venv.sh +++ b/templates/venv.sh @@ -9,24 +9,50 @@ export env_root=$CW_INSTALLATION_PATH/$CW_ENV_NAME/ cd $CW_INSTALLATION_PATH - cd $CW_WORKDIR source $CW_INSTALLATION_PATH/_pre_install.sh cd $CW_INSTALLATION_PATH -if [[ ${CW_ENABLE_SITE_PACKAGES+defined} ]];then - print_info "Enabling system and user site packages" 1 - _SP="--system-site-packages" -else - print_info "Not enabling system and user site packages" 1 - _SP="" + +_NC="" +if [[ "$CW_PIPCACHE" != "yes" ]]; then + _NC="-n" +fi + +if [[ "$CW_USE_UV" == "yes" ]]; then + if [[ ! -f "$CW_INSTALLATION_PATH/uv/bin/uv" ]]; then + print_info "Installing uv package manager" 1 + curl -LsSf https://astral.sh/uv/install.sh | env UV_UNMANAGED_INSTALL="$CW_INSTALLATION_PATH/uv/bin/" UV_PRINT_QUIET=1 sh + fi + export PATH="$CW_INSTALLATION_PATH/uv/bin/:$PATH" + export UV_PYTHON_INSTALL_DIR="$CW_INSTALLATION_PATH/uv/python" fi -print_info "Installing requirements file" 1 -python3 -m venv $_SP $CW_ENV_NAME -source $CW_INSTALLATION_PATH/$CW_ENV_NAME/bin/activate + +if [[ ! -e "$env_root/bin/activate" ]]; then + if [[ ${CW_ENABLE_SITE_PACKAGES+defined} ]];then + print_info "Enabling system and user site packages" 1 + _SP="--system-site-packages" + else + print_info "Not enabling system and user site packages" 1 + _SP="" + fi + print_info "Creating virtual environment" 1 + if [[ "$CW_USE_UV" == "yes" ]]; then + uv venv -p "$CW_PYVER" $_SP --managed-python $_NC --no-config --link-mode=copy "$env_root" + else + python3 -m venv $_SP "$CW_ENV_NAME" + fi +fi + +source "$env_root/bin/activate" if [[ ${CW_REQUIREMENTS_FILE+defined} ]];then - pip install --disable-pip-version-check -r "$( basename $CW_REQUIREMENTS_FILE)" > $CW_BUILD_TMPDIR/_pip.log & + print_info "Installing requirements file" 1 + if [[ "$CW_USE_UV" == "yes" ]]; then + uv pip install --link-mode=copy --compile-bytecode $_NC -r "$( basename "$CW_REQUIREMENTS_FILE")" > "$CW_BUILD_TMPDIR/_pip.log" & + else + pip install --disable-pip-version-check $_NC -r "$( basename "$CW_REQUIREMENTS_FILE")" > "$CW_BUILD_TMPDIR/_pip.log" & + fi bg_pid=$! wait $bg_pid follow_log $bg_pid $CW_BUILD_TMPDIR/_pip.log 20 diff --git a/templates/venv_modify.sh b/templates/venv_modify.sh deleted file mode 100644 index d8cd259..0000000 --- a/templates/venv_modify.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -set -e - - -cd $CW_BUILD_TMPDIR -echo "export env_root=$CW_INSTALLATION_PATH/$CW_ENV_NAME/" >> _extra_envs.sh -echo "export env_root=$CW_INSTALLATION_PATH/$CW_ENV_NAME/" >> _vars.sh -export env_root=$CW_INSTALLATION_PATH/$CW_ENV_NAME/ - -cd $CW_INSTALLATION_PATH - - -cd $CW_WORKDIR -source $CW_INSTALLATION_PATH/_pre_install.sh -cd $CW_INSTALLATION_PATH -source $CW_INSTALLATION_PATH/$CW_ENV_NAME/bin/activate -if [[ ${CW_REQUIREMENTS_FILE+defined} ]];then - print_info "Installing requirements file" 1 - pip install --disable-pip-version-check -r "$( basename $CW_REQUIREMENTS_FILE)" > $CW_BUILD_TMPDIR/_pip.log & - bg_pid=$! - wait $bg_pid - follow_log $bg_pid $CW_BUILD_TMPDIR/_pip.log 20 -fi -cd $CW_WORKDIR -#print_info "Running user supplied commands" 1 -source $CW_INSTALLATION_PATH/_post_install.sh - -echo "CW_WRAPPER_PATHS+=( \"$CW_INSTALLATION_PATH/$CW_ENV_NAME/bin/\" )" >> $CW_BUILD_TMPDIR/_vars.sh diff --git a/tests/tests.sh b/tests/tests.sh index f13a4d6..ae4acb7 100644 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -1,8 +1,9 @@ -#!/bin/bash -eu +#!/bin/bash -u SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" source $SCRIPT_DIR/setup.sh # Test are run in current directory +#cd "${TMPDIR:-/tmp}" rm -fr TEST_DIR mkdir TEST_DIR cd TEST_DIR @@ -32,6 +33,7 @@ done echo "pyyaml" > req.txt echo "pyyyaml" > req_typo.txt echo "pip install requests" > post.sh +echo "uv pip install requests" > post_uv.sh echo " channels: @@ -55,6 +57,16 @@ dependencies: " > conda_broken.yaml echo "GARBAGE" > conda_env.txt +echo " +channels: + - conda-forge +dependencies: + - numpy + - uv + - pip: + - requests +" > hybrid.yaml + t_run "conda-containerize new conda_base.yml --prefix NOT_A_DIR" "Missing install dir is created" mkdir A_DIR_NO_WRITE chmod ugo-w A_DIR_NO_WRITE @@ -72,7 +84,7 @@ t_run "test -z \"\$(grep ' DEBUG ' conda_inst.out )\" " "Default no debug messa tmp_dir=$(cat conda_inst.out | grep -o "[^ ]*/cw-[A-Z,0-9]\{6\} ") t_run "\[ ! -e $tmp_dir \]" "Build dir is deleted on error" export CW_DEBUG_KEEP_FILES=1 -conda-containerize new conda_broken.yaml --prefix CONDA_INSTALL_DIR > conda_inst.out +conda-containerize new conda_broken.yaml --prefix CONDA_INSTALL_DIR &> conda_inst.out tmp_dir=$(cat conda_inst.out | grep -o "[^ ]*/cw-[A-Z,0-9]\{6\} ") t_run "\[ -e $tmp_dir \]" "Build dir is saved if CW_DEBUG_KEEP_FILES set" test -d $tmp_dir && rm -rf $tmp_dir @@ -80,7 +92,7 @@ unset CW_DEBUG_KEEP_FILES unset CW_ENABLE_CONDARC echo "conda config --show-sources;conda config --show pkgs_dirs;exit 1" > pre.sh -rc_res=$(conda-containerize new --pre-install=pre.sh conda_base.yml --prefix CONDA_INSTALL_DIR | grep -o $HOME/.conda/pkgs) +rc_res=$(conda-containerize new --pre-install=pre.sh conda_base.yml --prefix CONDA_INSTALL_DIR 2>&1 | grep -o "$HOME/.conda/pkgs") t_run "test -z $rc_res" "User .condarc is ignored" export CW_ENABLE_CONDARC=1 t_run "conda-containerize new --pre-install=pre.sh conda_base.yml --prefix CONDA_INSTALL_DIR | grep -q $HOME/.conda/pkgs" "User .condarc can be enabled" @@ -97,12 +109,16 @@ t_run "CONDA_INSTALL_DIR/bin/python -c 'import requests'" "Package added by upda rm -fr CONDA_INSTALL_DIR && mkdir CONDA_INSTALL_DIR t_run "conda-containerize new --mamba explicit_env.txt --prefix CONDA_INSTALL_DIR &>/dev/null" "Explicit env file works" +rm -fr CONDA_INSTALL_DIR && mkdir CONDA_INSTALL_DIR +t_run "conda-containerize new --mamba --uv --prefix CONDA_INSTALL_DIR hybrid.yaml 2>&1 | grep -o 'Installing uv packages:'" "Hybrid conda/pip environment creation with uv" +t_run "conda-containerize update -r req.txt CONDA_INSTALL_DIR 2>&1 | grep -o 'Resolved 1 package in'" "Hybrid conda/pip environment update with uv" + rm -fr CONDA_INSTALL_DIR && mkdir CONDA_INSTALL_DIR t_run "conda-containerize new --mamba dask_env.yaml --prefix CONDA_INSTALL_DIR &>/dev/null" "yaml ending is also supported" OLD_PATH=$PATH PATH="CONDA_INSTALL_DIR/bin:$PATH" t_run " \[ $(which python)==$(_debug_exec which python) \] " "Which returns same in and out" -str1="$(python -c "print('Hello world --a g -b \ ')" )" +str1="$(python -c "print('Hello world --a g -b \\\ ')" )" str2="Hello world --a g -b \ " t_run "\[ \"$str1\" = \"$str2\" \]" "Wrapper passed quotes correctly" t_run "python -c \"import os; os.environ['CONDA_DEFAULT_ENV']\"" "Conda is activated" @@ -141,7 +157,7 @@ PATH=$OLD_PATH OLD_PATH=$PATH mkdir PIP_INSTALL_DIR -cat ../../default_config/config.yaml | sed 's/container_image.*$/container_image: My_very_cool_name.sif/g' > my_config.yaml +cat $SCRIPT_DIR/../default_config/config.yaml | sed 's/container_image.*$/container_image: My_very_cool_name.sif/g' > my_config.yaml t_run "pip-containerize new --prefix PIP_INSTALL_DIR req_typo.txt 2>&1 | grep 'No matching distribution'" "pip error shown to user" export CW_GLOBAL_YAML=my_config.yaml t_run "pip-containerize new --prefix PIP_INSTALL_DIR req.txt " "pip install works" @@ -153,3 +169,9 @@ t_run "python -c 'import sys;sys.exit(sys.prefix == sys.base_prefix)'" "Installa in_p=$(python3 -c 'import sys;print(sys.executable)') out_p="$PWD/PIP_INSTALL_DIR/bin/python3" t_run "[[ $in_p == $out_p ]]" "Executable name is same on in and out" +rm -fr PIP_INSTALL_DIR && mkdir PIP_INSTALL_DIR +t_run "pip-containerize new --uv --prefix PIP_UV_INSTALL_DIR req_typo.txt 2>&1 | grep -o 'not found in the package registry'" "uv error shown to user" +t_run "pip-containerize new --uv --prefix PIP_UV_INSTALL_DIR req.txt " "pip install with uv works" +t_run "pip-containerize update PIP_UV_INSTALL_DIR --post-install post_uv.sh" "Update with uv works" +t_run "PIP_UV_INSTALL_DIR/bin/python -c 'import requests'" "Package added in uv update available" +t_run "PIP_UV_INSTALL_DIR/bin/python -c 'import sys;sys.exit(sys.prefix == sys.base_prefix)'" "UV Installation is venv" diff --git a/tests/validate_slim.sh b/tests/validate_slim.sh index d6dc14b..d26d50a 100644 --- a/tests/validate_slim.sh +++ b/tests/validate_slim.sh @@ -3,15 +3,17 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" source $SCRIPT_DIR/setup.sh +#cd "${TMPDIR:-/tmp}" rm -rf TYKKY_V_TEST mkdir -p TYKKY_V_TEST cd TYKKY_V_TEST -echo "csvkit" > requirements.txt +echo "distro" > requirements.txt echo "pip install lxml" > extra.txt t_run "pip-containerize new --slim --prefix tykky_test requirements.txt" "Creating slim container works" -t_run "singularity exec tykky_test/container.sif cat /etc/os-release | grep 'Debian'" "Slim container is actually using debian" +t_run "tykky_test/bin/python -c 'import distro; print(distro.id())' | grep 'debian'" "Slim container is actually using debian" + t_run "pip-containerize update --post-install extra.txt tykky_test" "Updating a slim container works" t_run "pip-containerize new --slim --pyver 3.13.2-slim-bullseye --prefix tykky_test2 requirements.txt" "--pyver flag does not break" t_run "tykky_test2/bin/python --version | grep 'Python 3.13.2'" "Correct python version used"