From c6e86d5e77c79e7210c16acf28bf626c4f119b20 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Wed, 3 Jun 2026 05:39:42 -0700 Subject: [PATCH] Update Install Scripts (#5968) * Update Install Scripts Add SPDX AGPL-3.0 headers to the installer scripts and let the piped web installs take their common options from the environment. - install.sh / install.ps1: read UNSLOTH_NO_TORCH (and UNSLOTH_PYTHON for install.sh) so a piped install needs no positional flags. Flags and the pipe forms still work; an explicit flag wins. - Fix the UNSLOTH_STUDIO_HOME example so the variable sits after the pipe and reaches sh instead of curl. - Add SPDX headers to install.sh, install.ps1, the uninstall scripts, and the MLX install scripts. - Drop the internal test package names from the studio install comments. * Mirror UNSLOTH_PYTHON env var to install.ps1 install.ps1 now reads UNSLOTH_PYTHON to pin the Python version, matching install.sh, and lists all three env vars (UNSLOTH_NO_TORCH, UNSLOTH_PYTHON, UNSLOTH_STUDIO_HOME) in the header examples. The requested version is preferred during detection and used as the winget install target; behavior is unchanged when the variable is unset. --- install.ps1 | 35 +++++++++++++++++++++++----------- install.sh | 33 ++++++++++++++++++++------------ scripts/install_gemma4_mlx.sh | 2 ++ scripts/install_qwen3_6_mlx.sh | 2 ++ scripts/uninstall.ps1 | 3 +++ scripts/uninstall.sh | 3 +++ studio/install_python_stack.py | 4 ++-- studio/setup.ps1 | 2 +- 8 files changed, 58 insertions(+), 26 deletions(-) diff --git a/install.ps1 b/install.ps1 index 47c72bcdc..eb18e0d42 100644 --- a/install.ps1 +++ b/install.ps1 @@ -1,14 +1,20 @@ # Unsloth Studio Installer for Windows PowerShell -# Usage: irm https://raw.githubusercontent.com/unslothai/unsloth/main/install.ps1 | iex -# Local: Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass; .\install.ps1 --local -# NoTorch: .\install.ps1 --no-torch (skip PyTorch, GGUF-only mode) -# Test: .\install.ps1 --package roland-sloth # -# Env vars (priority: UNSLOTH_STUDIO_HOME > STUDIO_HOME > USERPROFILE-redirect > default): -# UNSLOTH_STUDIO_HOME / STUDIO_HOME = path -> install under that path -# (DataDir nests inside; user PATH not modified persistently). -# Default ($USERPROFILE\.unsloth\studio) is preserved when no env var is set. - +# Usage: irm https://unsloth.ai/install.ps1 | iex +# Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass; .\install.ps1 --local +# +# irm | iex cannot forward arguments, so web installs take options as env vars set +# before the pipe (flags still work via .\install.ps1): +# $env:UNSLOTH_NO_TORCH=1; irm https://unsloth.ai/install.ps1 | iex # skip PyTorch (GGUF-only) +# $env:UNSLOTH_PYTHON='3.12'; irm https://unsloth.ai/install.ps1 | iex # pin Python version +# $env:UNSLOTH_STUDIO_HOME='C:\path'; irm https://unsloth.ai/install.ps1 | iex +# .\install.ps1 --no-torch # equivalent flag +# Or pass flags to a scriptblock: & ([scriptblock]::Create((irm https://unsloth.ai/install.ps1))) --no-torch +# +# Install dir priority: UNSLOTH_STUDIO_HOME > STUDIO_HOME (alias) > $USERPROFILE\.unsloth\studio +# +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 function Install-UnslothStudio { $ErrorActionPreference = "Stop" $script:UnslothVerbose = ($env:UNSLOTH_VERBOSE -eq "1") @@ -112,6 +118,10 @@ function Install-UnslothStudio { } } } + + # Env-var equivalent for web installs; an explicit flag still wins. + if ($env:UNSLOTH_NO_TORCH -in @('1', 'true', 'yes', 'on')) { $SkipTorch = $true } + # Propagate to child processes so they also respect verbose mode. # Process-scoped -- does not persist. if ($script:UnslothVerbose) { @@ -132,7 +142,8 @@ function Install-UnslothStudio { return (Exit-InstallFailure "--package name contains invalid characters") } - $PythonVersion = "3.13" + # UNSLOTH_PYTHON pins the version (mirrors install.sh --python); default 3.13. + $PythonVersion = if ($env:UNSLOTH_PYTHON) { $env:UNSLOTH_PYTHON } else { "3.13" } # Resolve install destinations. Priority: UNSLOTH_STUDIO_HOME, then # STUDIO_HOME alias, then USERPROFILE-redirect, then default. @@ -935,7 +946,9 @@ shell.Run cmd, 0, False # py.exe resolves to the standard CPython install, not conda. $pyLauncher = Get-Command py -CommandType Application -ErrorAction SilentlyContinue if ($pyLauncher -and $pyLauncher.Source -notmatch $script:CondaSkipPattern) { - foreach ($minor in @("3.13", "3.12", "3.11")) { + # Prefer the requested $PythonVersion, then newest-first fallback. + $minors = @($PythonVersion) + (@("3.13", "3.12", "3.11") | Where-Object { $_ -ne $PythonVersion }) + foreach ($minor in $minors) { try { $out = & $pyLauncher.Source "-$minor" --version 2>&1 | Out-String if ($out -match "Python (3\.1[1-3])\.\d+") { diff --git a/install.sh b/install.sh index 15755c589..1d4d9067c 100755 --- a/install.sh +++ b/install.sh @@ -1,17 +1,22 @@ #!/bin/sh -# Unsloth Studio Installer -# Usage (curl): curl -fsSL https://unsloth.ai/install.sh | sh -# Usage (wget): wget -qO- https://unsloth.ai/install.sh | sh -# Usage (local): ./install.sh --local (install from local repo instead of PyPI) -# Usage (no-torch): ./install.sh --no-torch (skip PyTorch, GGUF-only mode) -# Usage (test): ./install.sh --package roland-sloth (install a different package name) -# Usage (py): ./install.sh --python 3.12 (override auto-detected Python version) # -# Env vars (priority: UNSLOTH_STUDIO_HOME > STUDIO_HOME > HOME-redirect > default): -# UNSLOTH_STUDIO_HOME=/abs/path -> install under that path -# STUDIO_HOME=/abs/path -> alias, same effect (UNSLOTH_STUDIO_HOME wins) -# (DATA_DIR + unsloth CLI shim nest inside; no shell rc-file append.) -# Default ($HOME/.unsloth/studio) is preserved when no env var is set. +# Unsloth Studio Installer +# +# Usage: curl -fsSL https://unsloth.ai/install.sh | sh +# wget -qO- https://unsloth.ai/install.sh | sh +# ./install.sh --local (install from a cloned repo instead of PyPI) +# +# Piped installs take options as env vars after the pipe (a bare `| sh --no-torch` +# makes sh reject --no-torch as its own option). Flags still work via ./install.sh: +# curl -fsSL https://unsloth.ai/install.sh | UNSLOTH_NO_TORCH=1 sh # skip PyTorch (GGUF-only) +# curl -fsSL https://unsloth.ai/install.sh | UNSLOTH_PYTHON=3.12 sh # pin Python version +# curl -fsSL https://unsloth.ai/install.sh | UNSLOTH_STUDIO_HOME=/abs/path sh +# Equivalent flags: ./install.sh --no-torch --python 3.12 (or pipe them: sh -s -- --no-torch) +# +# Install dir priority: UNSLOTH_STUDIO_HOME > STUDIO_HOME (alias) > $HOME/.unsloth/studio +# +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 set -e # ── Output style (aligned with studio/setup.sh) ── @@ -70,6 +75,10 @@ for arg in "$@"; do esac done +# Env-var equivalents for piped installs; an explicit flag still wins. +case "${UNSLOTH_NO_TORCH:-}" in 1|true|TRUE|yes|YES|on|ON) _NO_TORCH_FLAG=true ;; esac +[ -z "$_USER_PYTHON" ] && [ -n "${UNSLOTH_PYTHON:-}" ] && _USER_PYTHON="$UNSLOTH_PYTHON" + if [ "$_VERBOSE" = true ]; then export UNSLOTH_VERBOSE=1 fi diff --git a/scripts/install_gemma4_mlx.sh b/scripts/install_gemma4_mlx.sh index e1f43b827..e1ac4628f 100755 --- a/scripts/install_gemma4_mlx.sh +++ b/scripts/install_gemma4_mlx.sh @@ -1,4 +1,6 @@ #!/bin/bash +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 set -euo pipefail # ============================================================ diff --git a/scripts/install_qwen3_6_mlx.sh b/scripts/install_qwen3_6_mlx.sh index 38fe1bea0..ef0a3ee9e 100644 --- a/scripts/install_qwen3_6_mlx.sh +++ b/scripts/install_qwen3_6_mlx.sh @@ -1,4 +1,6 @@ #!/bin/bash +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 set -euo pipefail # ============================================================ diff --git a/scripts/uninstall.ps1 b/scripts/uninstall.ps1 index 6174e7e49..25dd4af01 100644 --- a/scripts/uninstall.ps1 +++ b/scripts/uninstall.ps1 @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 +# # Unsloth Studio uninstaller for Windows PowerShell. # Stops running servers and removes install dir, launcher data, CLI shim, # desktop and Start Menu shortcuts, the user PATH entry, and the PathBackup diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index 94ca04b20..bb830151a 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -1,4 +1,7 @@ #!/usr/bin/env sh +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 +# # Unsloth Studio uninstaller (macOS / Linux / WSL). # Stops running servers and removes install dir, launcher data, # CLI shim, desktop shortcut, .app bundle, and Launch Services entry. diff --git a/studio/install_python_stack.py b/studio/install_python_stack.py index 5e785c934..da202f7ce 100644 --- a/studio/install_python_stack.py +++ b/studio/install_python_stack.py @@ -1406,7 +1406,7 @@ def install_python_stack() -> int: # When called from "unsloth studio update", it is NOT set so base packages # (unsloth + unsloth-zoo) are always reinstalled to pick up new versions. skip_base = os.environ.get("SKIP_STUDIO_BASE", "0") == "1" - # When --package is used, install a different package name (e.g. roland-sloth for testing) + # When --package is used, install a different package name (for testing) package_name = os.environ.get("STUDIO_PACKAGE_NAME", "unsloth") # When --local is used, overlay a local repo checkout after updating deps local_repo = os.environ.get("STUDIO_LOCAL_REPO", "") @@ -1565,7 +1565,7 @@ def install_python_stack() -> int: constrain = False, ) elif package_name != "unsloth": - # Custom package name (e.g. roland-sloth for testing) — install directly + # Custom package name (for testing), install directly _progress("base packages") pip_install( f"Installing {package_name}", diff --git a/studio/setup.ps1 b/studio/setup.ps1 index 28ad51269..4d4701013 100644 --- a/studio/setup.ps1 +++ b/studio/setup.ps1 @@ -2016,7 +2016,7 @@ if ($env:SKIP_STUDIO_BASE -ne "1" -and $env:STUDIO_LOCAL_INSTALL -ne "1") { # # the fresh .venv. Install it so run_install() can find its modules # # and bundled requirements files. # Write-Host " Installing package into venv..." -ForegroundColor Cyan -# pip install unsloth-roland-test 2>&1 | Out-Null +# pip install unsloth 2>&1 | Out-Null # } if (-not $SkipPythonDeps) {