diff --git a/omnigibson/download_datasets.py b/omnigibson/download_datasets.py index 1e4d73df9..f850e50e7 100644 --- a/omnigibson/download_datasets.py +++ b/omnigibson/download_datasets.py @@ -23,7 +23,7 @@ def main(): print( f"If you want to install data under a different path, please change the DATA_PATH variable in omnigibson/macros.py and rerun omnigibson/download_datasets.py." ) - if click.confirm("Do you want to continue?"): + if click.confirm("Do you want to continue?", default=True): # Only download if the dataset path doesn't exist if not dataset_exists: print("Downloading dataset...") diff --git a/omnigibson/install.py b/omnigibson/install.py new file mode 100644 index 000000000..c45b98ca7 --- /dev/null +++ b/omnigibson/install.py @@ -0,0 +1,345 @@ +import os +import platform +import subprocess +import sys +import tempfile +import urllib.request +from pathlib import Path +from typing import Optional + +import click +import pip + +from omnigibson.macros import gm +from omnigibson.utils.asset_utils import download_assets, download_og_dataset + +# List of NVIDIA PyPI packages needed for OmniGibson +ISAAC_SIM_PACKAGES = [ + "omniverse_kit-106.1.0.140981", + "isaacsim_kernel-4.2.0.2", + "isaacsim_app-4.2.0.2", + "isaacsim_core-4.2.0.2", + "isaacsim_gui-4.2.0.2", + "isaacsim_utils-4.2.0.2", + "isaacsim_storage-4.2.0.2", + "isaacsim_asset-4.2.0.2", + "isaacsim_sensor-4.2.0.2", + "isaacsim_robot_motion-4.2.0.2", + "isaacsim_robot-4.2.0.2", + "isaacsim_benchmark-4.2.0.2", + "isaacsim_code_editor-4.2.0.2", + "isaacsim_ros1-4.2.0.2", + "isaacsim_cortex-4.2.0.2", + "isaacsim_example-4.2.0.2", + "isaacsim_replicator-4.2.0.2", + "isaacsim_rl-4.2.0.2", + "isaacsim_robot_setup-4.2.0.2", + "isaacsim_ros2-4.2.0.2", + "isaacsim_template-4.2.0.2", + "isaacsim_test-4.2.0.2", + "isaacsim-4.2.0.2", + "isaacsim_extscache_physics-4.2.0.2", + "isaacsim_extscache_kit-4.2.0.2", + "isaacsim_extscache_kit_sdk-4.2.0.2", +] +BASE_URL = "https://pypi.nvidia.com" + + +def _find_isaac_sim_path(): + """Try to find the path of a launcher-based Isaac Sim installation.""" + if platform.system() == "Windows": + base_path = Path.home() / "AppData" / "Local" / "ov" / "pkg" + else: + base_path = Path.home() / ".local" / "share" / "ov" / "pkg" + + # If the pkg dir is missing, we definitely can't find an Isaac Sim installation + if not base_path.exists(): + return None + + isaac_dirs = list(base_path.glob("isaac*")) + if not isaac_dirs: + return None + + return isaac_dirs[-1] + + +def _get_filename(package: str, temp_dir: Path): + if platform.system() == "Windows": + return temp_dir / f"{package}-cp310-win_amd64.whl" + return temp_dir / f"{package}-cp310-none-manylinux_2_34_x86_64.whl" + + +def _download_package(url: str, filename: Path): + try: + urllib.request.urlretrieve(url, filename) + except Exception as e: + raise ValueError(f"Failed to download {url}") from e + + +def _rename_if_necessary(filename: Path): + """ + Rename the file if the system's GLIBC version is older than the one used in the NVIDIA PyPI packages. + + This is permissible because the manylinux wheels are compatible with older GLIBC versions even though + the filename suggests not - so we apply this hacky workaround. This allows pip to try to install them. + """ + if platform.system() == "Linux" and _is_glibc_older(): + return filename.with_name(filename.name.replace("manylinux_2_34", "manylinux_2_31")) + return filename + + +def _is_glibc_older(): + """Check if the system's GLIBC version is older than the one used in the NVIDIA PyPI packages.""" + try: + dist_info = subprocess.check_output(["ldd", "--version"]).decode("utf-8") + if any(version in dist_info for version in ["2.31", "2.32", "2.33"]): + return True + elif any(version in dist_info for version in ["2.34", "2.35", "2.36", "2.37", "2.38", "2.39"]): + return False + else: + raise ValueError("Incompatible GLIBC version") + except subprocess.CalledProcessError: + raise ValueError("Failed to check GLIBC version. `ldd` was not accessible. Try running it yourself to see why.") + + +def _pip_install(filename: Path): + """Install a package using pip.""" + try: + pip.main(["install", str(filename)]) + except Exception as e: + raise ValueError(f"Failed to install {filename}") from e + + +def _install_isaac_sim_package(package: str, temp_dir: Path): + package_name = package.split("-")[0].replace("_", "-") + filename = _get_filename(package, temp_dir) + url = f"{BASE_URL}/{package_name}/{filename}" + + try: + _download_package(url, filename) + _pip_install(_rename_if_necessary(filename)) + except Exception as e: + click.echo(f"Failed to install {package}: {str(e)}") + raise + + +def _setup_windows_conda_env(isaac_sim_path: Path, conda_prefix: Path): + # Create directories + for dir_name in ["activate.d", "deactivate.d"]: + os.makedirs(conda_prefix / "etc" / "conda" / dir_name, exist_ok=True) + + # Create empty files + for file_name in ["env_vars.bat", "env_vars.ps1"]: + for dir_name in ["activate.d", "deactivate.d"]: + (conda_prefix / "etc" / "conda" / dir_name / file_name).touch() + + # Setup CMD activation script + cmd_act_file = conda_prefix / "etc" / "conda" / "activate.d" / "env_vars.bat" + with cmd_act_file.open("w") as f: + f.write("@echo off\n") + f.write("set PYTHONPATH_OLD=%PYTHONPATH%\n") + f.write(f"set PYTHONPATH=%PYTHONPATH%;{isaac_sim_path}\\site\n") + f.write(f"set CARB_APP_PATH={isaac_sim_path}\\kit\n") + f.write(f"set EXP_PATH={isaac_sim_path}\\apps\n") + f.write(f"set ISAAC_PATH={isaac_sim_path}\n") + + # Setup CMD deactivation script + cmd_deact_file = conda_prefix / "etc" / "conda" / "deactivate.d" / "env_vars.bat" + with cmd_deact_file.open("w") as f: + f.write("@echo off\n") + f.write("set PYTHONPATH=%PYTHONPATH_OLD%\n") + f.write('set PYTHONPATH_OLD=""\n') + + # Setup PowerShell activation script + ps_act_file = conda_prefix / "etc" / "conda" / "activate.d" / "env_vars.ps1" + with ps_act_file.open("w") as f: + f.write('$env:PYTHONPATH_OLD="$env:PYTHONPATH"\n') + f.write(f'$env:PYTHONPATH="$env:PYTHONPATH;{isaac_sim_path}\\site"\n') + f.write(f'$env:CARB_APP_PATH="{isaac_sim_path}\\kit"\n') + f.write(f'$env:EXP_PATH="{isaac_sim_path}\\apps"\n') + f.write(f'$env:ISAAC_PATH="{isaac_sim_path}"\n') + + # Setup PowerShell deactivation script + ps_deact_file = conda_prefix / "etc" / "conda" / "deactivate.d" / "env_vars.ps1" + with ps_deact_file.open("w") as f: + f.write('$env:PYTHONPATH="$env:PYTHONPATH_OLD"\n') + f.write('$env:PYTHONPATH_OLD="$null"\n') + + +def _setup_unix_conda_env(isaac_sim_path: Path, conda_prefix: Path): + # Set up conda environment files + for dir_name in ["activate.d", "deactivate.d"]: + os.makedirs(conda_prefix / "etc" / "conda" / dir_name, exist_ok=True) + + # Create activation script + with open(conda_prefix / "etc" / "conda" / "activate.d" / "env_vars.sh", "w") as f: + f.write("#!/bin/sh\n") + f.write("export LD_LIBRARY_PATH_OLD=$LD_LIBRARY_PATH\n") + f.write("export PYTHONPATH_OLD=$PYTHONPATH\n") + f.write(f"source {isaac_sim_path}/setup_conda_env.sh\n") + + # Create deactivation script + with open(conda_prefix / "etc" / "conda" / "deactivate.d" / "env_vars.sh", "w") as f: + f.write("#!/bin/sh\n") + f.write("export LD_LIBRARY_PATH=$LD_LIBRARY_PATH_OLD\n") + f.write("export PYTHONPATH=$PYTHONPATH_OLD\n") + f.write("unset ISAAC_PATH\n") + f.write("unset CARB_APP_PATH\n") + f.write("unset LD_LIBRARY_PATH_OLD\n") + f.write("unset PYTHONPATH_OLD\n") + + +def _launcher_based_install(isaac_sim_path: Optional[Path]): + # If we are using a launcher-based installation, we need to find the path to the Isaac Sim installation + if isaac_sim_path is None: + isaac_sim_path = _find_isaac_sim_path() + + # If it's not at the provided or default path, remove it + if isaac_sim_path is None or not list(Path(isaac_sim_path).glob("isaac*.*")): + return False + + # Update conda environment files to point to the specified Isaac Sim installation + conda_prefix = Path(os.environ["CONDA_PREFIX"]) + if platform.system() == "Windows": + _setup_windows_conda_env(isaac_sim_path, conda_prefix) + else: + _setup_unix_conda_env(isaac_sim_path, conda_prefix) + + return True + + +def _pip_based_install(): + try: + # Create a temporary directory to download the packages + with tempfile.TemporaryDirectory() as temp_dir: + # Install all required packages + for package in ISAAC_SIM_PACKAGES: + _install_isaac_sim_package(package, temp_dir) + + # Check that it can now be imported + import isaacsim + except ImportError: + return False + + return True + + +def attempt_launcher_install(isaac_sim_path: Optional[Path]): + click.echo("Checking for an existing launcher-based Isaac Sim installation...") + success = _launcher_based_install(isaac_sim_path) + if success: + click.echo("Successfully found and attached to launcher-based Isaac Sim installation.") + else: + click.echo("We did not find Isaac Sim installed via the launcher.") + return success + + +def attempt_pip_install(): + click.echo("We will now try to install Isaac Sim via pip.") + success = _pip_based_install() + if success: + click.echo("Successfully installed Isaac Sim via pip.") + else: + click.echo("Failed to import isaacsim. Something went wrong during the pip installation.") + return success + + +@click.command() +@click.option( + "--install-datasets", default=True, help="Install the OmniGibson dataset and assets after installing Isaac Sim" +) +@click.option( + "--force-pip-install", + default=False, + help="Install Isaac Sim via pip even if a launcher-based installation is found", +) +@click.option( + "--force-launcher-install", + default=False, + help="Do not install Isaac Sim via pip even if a launcher-based installation is not found", +) +@click.option( + "--isaac-sim-path", + type=click.Path(exists=True, dir_okay=True, file_okay=False, writeable=True, readable=True, path_type=Path), + default=None, + help="Path to the existing launcher-based Isaac Sim installation directory, to force the setup script to use it", +) +def setup_omnigibson( + install_datasets: bool, force_pip_install: bool, force_launcher_install: bool, isaac_sim_path: Optional[Path] +): + if force_pip_install and force_launcher_install: + click.echo("You can't force both pip and launcher-based installations at the same time.") + return + + # Check that we are in a conda environment + if "CONDA_PREFIX" not in os.environ: + click.echo("Please run this script from within a conda environment.") + click.echo("You can create one by running `conda create -n omnigibson python=3.10`.") + return + + # Check that the current interpreter is Python 3.10 + if sys.version_info[:2] != (3, 10): + click.echo("Please run this script with Python 3.10.") + return + + # First, try to install Isaac Sim via the launcher + installation_successful = False + if not force_pip_install: + installation_successful = attempt_launcher_install(isaac_sim_path) + + # If that failed, try to install it via pip + if not installation_successful: + if force_launcher_install: + # If the user forced a launcher-based installation, we should not try to install via pip + click.echo("You forced the script to use a launcher-based installation, but we couldn't find it.") + click.echo("Please make sure you have installed Isaac Sim correctly before running this setup script.") + else: + installation_successful = attempt_pip_install() + + # If neither installation was successful, we should exit + if not installation_successful: + click.echo("Failed to install Isaac Sim. Please check the installation requirements and try again.") + return + + # Now prompt the user to install the dataset and assets + click.echo("Isaac Sim has been successfully installed.") + + if install_datasets: + click.echo("We will now install the datasets.") + + # Only execute if the dataset path or asset path does not exist + dataset_exists, assets_exist = os.path.exists(gm.DATASET_PATH), os.path.exists(gm.ASSET_PATH) + if not (dataset_exists and assets_exist): + # Ask user which dataset to install + click.echo(f"OmniGibson will now install data under the following locations:") + click.echo(f" dataset (~25GB): {gm.DATASET_PATH}") + click.echo(f" assets (~2.5GB): {gm.ASSET_PATH}") + click.echo( + f"If you want to install data under a different path, please change the DATA_PATH variable in omnigibson/macros.py and " + f"rerun omnigibson/download_datasets.py." + ) + if click.confirm("Do you want to continue?", default=True): + # Only download if the dataset path doesn't exist + if not dataset_exists: + click.echo("Downloading dataset...") + download_og_dataset() + + # Only download if the asset path doesn't exist + if not assets_exist: + click.echo("Downloading assets...") + download_assets() + else: + click.echo( + "You chose not to install dataset for now. You can install it later by running python omnigibson/download_datasets.py." + ) + + click.echo( + "\nOmniGibson setup completed! You can now run your experiments. " + "Visit https://behavior.stanford.edu/omnigibson/getting_started/examples.html for some examples, " + "and https://behavior.stanford.edu/omnigibson-develop/getting_started/quickstart.html for a quickstart " + "guide for working with OmniGibson APIs." + ) + + +if __name__ == "__main__": + setup_omnigibson() diff --git a/scripts/setup.bat b/scripts/setup.bat deleted file mode 100644 index 651ce3887..000000000 --- a/scripts/setup.bat +++ /dev/null @@ -1,92 +0,0 @@ -@echo off -:: Make sure that the ISAAC_SIM_PATH variable is set correctly -dir /b /o:-n %userprofile%\AppData\Local\ov\pkg\isaac_sim* > NUL -if errorlevel 0 ( - for /f "tokens=* usebackq" %%f in (`dir /b /o:n %userprofile%\AppData\Local\ov\pkg\isaac_sim*`) do set ISAAC_SIM_PATH=%userprofile%\AppData\Local\ov\pkg\%%f - setlocal enabledelayedexpansion - echo We found Isaac Sim installed at !ISAAC_SIM_PATH!. OmniGibson will use it by default. - endlocal - set /p ISAAC_SIM_PATH=If you want to use a different one, please type in the path containing isaac-sim.bat here ^(press enter to skip^) ^>^>^> -) else ( - echo We did not find Isaac Sim under %userprofile%\AppData\Local\ov\pkg. - echo If you haven't installed Isaac Sim yet, please do so before running this setup script. - set /p ISAAC_SIM_PATH=If you have already installed it in a custom location, please type in the path containing isaac-sim.bat here ^>^>^> -) -:check_isaac_sim_path -if not exist %ISAAC_SIM_PATH%\isaac*.bat ( - set /p ISAAC_SIM_PATH=isaac*.bat not found in %ISAAC_SIM_PATH%! Make sure you have entered the correct path ^>^>^> - goto :check_isaac_sim_path -) -echo: -echo Using Isaac Sim at %ISAAC_SIM_PATH% -echo: - -:: Choose venv name -set conda_name=omnigibson -echo The new conda environment will be named omnigibson by default. -set /p conda_name=If you want to use a different name, please type in here ^(press enter to skip^) ^>^>^> -echo: -echo Using %conda_name% as the conda environment name -echo: - -:: Get Python version from Isaac Sim -FOR /F "tokens=*" %%g IN ('%ISAAC_SIM_PATH%\python.bat -c "import platform; print(platform.python_version())"') do (SET ISAAC_PYTHON_VERSION=%%g) -echo Using Python version %ISAAC_PYTHON_VERSION% matching your current Isaac Sim version - -:: Create a conda environment with the appropriate python version -call conda create -y -n %conda_name% python=%ISAAC_PYTHON_VERSION% || goto :error -call conda activate %conda_name% || goto :error - -:: We add some preprocessing information so that the Isaac Sim paths are linked to this environment upon startup -:: See https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#macos-and-linux for reference -mkdir %CONDA_PREFIX%\etc\conda\activate.d -mkdir %CONDA_PREFIX%\etc\conda\deactivate.d -type NUL>%CONDA_PREFIX%\etc\conda\activate.d\env_vars.bat -type NUL>%CONDA_PREFIX%\etc\conda\deactivate.d\env_vars.bat -type NUL>%CONDA_PREFIX%\etc\conda\activate.d\env_vars.ps1 -type NUL>%CONDA_PREFIX%\etc\conda\deactivate.d\env_vars.ps1 - -:: Add support for cmd -set CONDA_ACT_FILE_CMD=%CONDA_PREFIX%\etc\conda\activate.d\env_vars.bat -echo @echo off>>%CONDA_ACT_FILE_CMD% -echo set PYTHONPATH_OLD=%%PYTHONPATH%%>>%CONDA_ACT_FILE_CMD% -echo set PYTHONPATH=%%PYTHONPATH%%;%ISAAC_SIM_PATH%\site>>%CONDA_ACT_FILE_CMD% -echo set CARB_APP_PATH=%ISAAC_SIM_PATH%\kit>>%CONDA_ACT_FILE_CMD% -echo set EXP_PATH=%ISAAC_SIM_PATH%\apps>>%CONDA_ACT_FILE_CMD% -echo set ISAAC_PATH=%ISAAC_SIM_PATH%>>%CONDA_ACT_FILE_CMD% - -set CONDA_DEACT_FILE_CMD=%CONDA_PREFIX%\etc\conda\deactivate.d\env_vars.bat -echo @echo off>>%CONDA_DEACT_FILE_CMD% -echo set PYTHONPATH=%%PYTHONPATH_OLD%%>>%CONDA_DEACT_FILE_CMD% -echo set PYTHONPATH_OLD="">>%CONDA_DEACT_FILE_CMD% - -:: Add support for powershell -set CONDA_ACT_FILE_PWSH=%CONDA_PREFIX%\etc\conda\activate.d\env_vars.ps1 -echo $env:PYTHONPATH_OLD="$env:PYTHONPATH">>%CONDA_ACT_FILE_PWSH% -echo $env:PYTHONPATH="$env:PYTHONPATH;%ISAAC_SIM_PATH%\site">>%CONDA_ACT_FILE_PWSH% -echo $env:CARB_APP_PATH="%ISAAC_SIM_PATH%\kit">>%CONDA_ACT_FILE_PWSH% -echo $env:EXP_PATH="%ISAAC_SIM_PATH%\apps">>%CONDA_ACT_FILE_PWSH% -echo $env:ISAAC_PATH="%ISAAC_SIM_PATH%">>%CONDA_ACT_FILE_PWSH% - -set CONDA_DEACT_FILE_PWSH=%CONDA_PREFIX%\etc\conda\deactivate.d\env_vars.ps1 -echo $env:PYTHONPATH="$env:PYTHONPATH_OLD">>%CONDA_DEACT_FILE_PWSH% -echo $env:PYTHONPATH_OLD="$null">>%CONDA_DEACT_FILE_PWSH% - - -:: Install omnigibson! -call pip install -e . || goto :error - -:: Cycle conda environment so that all dependencies are propagated -call conda deactivate || goto :error -goto :end - -:error -echo: -echo An error occurred during installation. Please check the error message above. -echo: -exit /b - -:end -echo: -echo OmniGibson successfully installed! Please run conda activate %conda_name% to activate the environment. -echo: diff --git a/scripts/setup.sh b/scripts/setup.sh deleted file mode 100755 index 4f34e0ea5..000000000 --- a/scripts/setup.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env bash -set -eo &> /dev/null - -# Make sure that the ISAAC_SIM_PATH variable is set correctly -if [[ -d ~/.local/share/ov/pkg ]] && [[ $(ls ~/.local/share/ov/pkg | grep isaac) ]]; -then - FOUND_ISAAC_SIM_PATH=$(ls -d ~/.local/share/ov/pkg/* | grep isaac | tail -n 1) - echo "We found Isaac Sim installed at $FOUND_ISAAC_SIM_PATH. OmniGibson will use it by default." - read -p "If you want to use a different one, please type in the path containing isaac-sim.sh here (press enter to skip) >>> " ISAAC_SIM_PATH - ISAAC_SIM_PATH=${ISAAC_SIM_PATH:-$FOUND_ISAAC_SIM_PATH} -else - echo "We did not find Isaac Sim under ~/.local/share/ov/pkg." - echo "If you haven't installed Isaac Sim yet, please do so before running this setup script." - read -p "If you have already installed it in a custom location, please type in the path containing isaac-sim.sh here >>> " ISAAC_SIM_PATH -fi - -while [[ ! -n $(find "${ISAAC_SIM_PATH}" -maxdepth 1 -name "isaac*.sh" 2>/dev/null) ]]; do - read -p "isaac*.sh not found in $ISAAC_SIM_PATH! Make sure you have entered the correct path >>> " ISAAC_SIM_PATH -done -echo -e "\nUsing Isaac Sim at $ISAAC_SIM_PATH\n" - - -# Choose venv name -echo "The new conda environment will be named omnigibson by default." -read -p "If you want to use a different name, please type in here (press enter to skip) >>> " conda_name -conda_name=${conda_name:-omnigibson} -echo -e "\nUsing $conda_name as the conda environment name\n" - -# Get Python version from Isaac Sim -ISAAC_PYTHON_VERSION=$(${ISAAC_SIM_PATH}/python.sh -c "import platform; print(platform.python_version())") -ISAAC_PYTHON_VERSION="${ISAAC_PYTHON_VERSION##*$'\n'}" # get rid of conda activation warnings -echo Using Python version $ISAAC_PYTHON_VERSION matching your current Isaac Sim version - -# Create a conda environment with the appropriate python version -source $(conda info --base)/etc/profile.d/conda.sh -conda create -y -n $conda_name python=${ISAAC_PYTHON_VERSION} - -# Now activate the omnigibson environment -conda activate $conda_name - -mkdir -p ${CONDA_PREFIX}/etc/conda/activate.d -mkdir -p ${CONDA_PREFIX}/etc/conda/deactivate.d -touch ${CONDA_PREFIX}/etc/conda/activate.d/env_vars.sh -touch ${CONDA_PREFIX}/etc/conda/deactivate.d/env_vars.sh -# We add some preprocessing information so that the Isaac Sim paths are linked to this environment upon startup -# See https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#macos-and-linux for reference -CONDA_ACT_FILE="${CONDA_PREFIX}/etc/conda/activate.d/env_vars.sh" -echo '#!/bin/sh' > ${CONDA_ACT_FILE} -echo "export LD_LIBRARY_PATH_OLD=\$LD_LIBRARY_PATH" >> ${CONDA_ACT_FILE} -echo "export PYTHONPATH_OLD=\$PYTHONPATH" >> ${CONDA_ACT_FILE} -echo "source ${ISAAC_SIM_PATH}/setup_conda_env.sh" >> ${CONDA_ACT_FILE} - -CONDA_DEACT_FILE="${CONDA_PREFIX}/etc/conda/deactivate.d/env_vars.sh" -echo '#!/bin/sh' > ${CONDA_DEACT_FILE} -echo "export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH_OLD" >> ${CONDA_DEACT_FILE} -echo "export PYTHONPATH=\$PYTHONPATH_OLD" >> ${CONDA_DEACT_FILE} -echo "unset ISAAC_PATH" >> ${CONDA_DEACT_FILE} -echo "unset CARB_APP_PATH" >> ${CONDA_DEACT_FILE} -echo "unset LD_LIBRARY_PATH_OLD" >> ${CONDA_DEACT_FILE} -echo "unset PYTHONPATH_OLD" >> ${CONDA_DEACT_FILE} - -# Install omnigibson! -pip install -e . - -# Cycle conda environment so that all dependencies are propagated -conda deactivate - -echo -e "\nOmniGibson successfully installed! Please run conda activate $conda_name to activate the environment.\n"