Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 131 additions & 28 deletions install.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[CmdletBinding()]
param(
[string]$InstallDir = (Join-Path $HOME "ToCode"),
[string]$InstallDir,
[string]$Repo = "https://github.com/buzzer-re/ToCode.git",
[string]$Branch = "main",
[switch]$Dev
Expand All @@ -9,17 +9,63 @@ param(
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

$script:PathWasUpdated = $false

# When run from an existing ToCode checkout, install from it instead of
# cloning a second copy. $PSScriptRoot is empty when piped through iex.
$scriptDir = $PSScriptRoot
if (-not $InstallDir) {
if ($scriptDir -and (Test-Path (Join-Path $scriptDir ".git")) -and (Test-Path (Join-Path $scriptDir "pyproject.toml"))) {
$InstallDir = $scriptDir
}
else {
$InstallDir = Join-Path $HOME "ToCode"
}
}

function Write-Step {
param([string]$Message)
Write-Host "==> $Message"
}

function Fail {
param([string]$Message)
Write-Error "install.ps1: $Message"
param(
[string]$Message,
[string[]]$Hints = @()
)
Write-Host ""
Write-Host "ToCode was not installed: $Message" -ForegroundColor Red
foreach ($hint in $Hints) {
Write-Host " $hint" -ForegroundColor Yellow
}
exit 1
}

function Assert-NativeSuccess {
param(
[string]$Message,
[string[]]$Hints = @()
)
if ($LASTEXITCODE -ne 0) {
Fail "$Message (exit code $LASTEXITCODE)." $Hints
}
}

# Runs a native command with stderr suppressed. Under
# $ErrorActionPreference = "Stop", Windows PowerShell turns redirected native
# stderr into a terminating NativeCommandError, so relax the preference first.
function Invoke-Quiet {
param([scriptblock]$Command)
$previous = $ErrorActionPreference
$ErrorActionPreference = "Continue"
try {
& $Command 2>$null
}
finally {
$ErrorActionPreference = $previous
}
}

function Test-Command {
param([string]$Name)
return $null -ne (Get-Command $Name -ErrorAction SilentlyContinue)
Expand All @@ -38,16 +84,16 @@ function Get-PythonCommand {
continue
}

$args = @()
$extraArgs = @()
if ($candidate.Count -gt 1) {
$args = $candidate[1..($candidate.Count - 1)]
$extraArgs = $candidate[1..($candidate.Count - 1)]
}

& $name @args -c "import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)" 2>$null
Invoke-Quiet { & $name @extraArgs -c "import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)" } | Out-Null
if ($LASTEXITCODE -eq 0) {
return @{
Name = $name
Args = $args
Args = $extraArgs
}
}
}
Expand Down Expand Up @@ -98,30 +144,47 @@ function Add-UserPath {
if ($missingFromPersistentPath) {
$newUserPath = if ($userPath) { "$userPath;$BinDir" } else { $BinDir }
[Environment]::SetEnvironmentVariable("Path", $newUserPath, "User")
$script:PathWasUpdated = $true
Write-Step "Added $BinDir to your user Path"
Write-Host "Open a new PowerShell or cmd session before running tocode outside this installer."
}
}

if (-not (Test-Command "git")) {
Fail "git is required but was not found on PATH"
Fail "Git was not found on PATH." @(
"Install Git for Windows from https://git-scm.com/download/win, then run this installer again."
)
}

$gitDir = Join-Path $InstallDir ".git"
if (Test-Path $gitDir) {
Write-Step "Updating ToCode at $InstallDir"
git -C $InstallDir fetch origin $Branch
git -C $InstallDir checkout $Branch
git -C $InstallDir pull --ff-only origin $Branch
if ($scriptDir -and ((Resolve-Path $InstallDir).Path.TrimEnd('\') -ieq (Resolve-Path $scriptDir).Path.TrimEnd('\'))) {
Write-Step "Installing ToCode from this checkout at $InstallDir"
}
else {
Write-Step "Updating ToCode at $InstallDir"
git -C $InstallDir fetch origin $Branch
Assert-NativeSuccess "could not fetch branch '$Branch' from origin"
git -C $InstallDir checkout $Branch
Assert-NativeSuccess "could not check out branch '$Branch' in $InstallDir"
git -C $InstallDir pull --ff-only origin $Branch
Assert-NativeSuccess "could not update the checkout at $InstallDir" @(
"The checkout may have local changes. Resolve them, or remove the directory and run this installer again."
)
}
}
elseif (Test-Path $InstallDir) {
Fail "$InstallDir already exists and is not a Git checkout"
Fail "$InstallDir already exists and is not a ToCode Git checkout." @(
"Move or delete it, or pick another location with: .\install.ps1 -InstallDir <path>"
)
}
else {
Write-Step "Cloning ToCode into $InstallDir"
git clone --branch $Branch $Repo $InstallDir
Assert-NativeSuccess "could not clone $Repo"
}

$binDir = $null

if (Test-Command "uv") {
Write-Step "Syncing local project environment with uv"
if ($Dev) {
Expand All @@ -130,21 +193,24 @@ if (Test-Command "uv") {
else {
uv --directory $InstallDir sync --locked
}
Assert-NativeSuccess "uv could not sync the project environment"

Write-Step "Installing the tocode command with uv"
uv tool install --force --editable $InstallDir
Assert-NativeSuccess "uv could not install the tocode command"

if (-not (Test-Command "tocode")) {
$toolBin = (& uv tool dir --bin 2>$null)
if ($LASTEXITCODE -eq 0 -and $toolBin) {
Add-UserPath -BinDir $toolBin
}
$toolBin = Invoke-Quiet { uv tool dir --bin }
if ($LASTEXITCODE -eq 0 -and $toolBin) {
$binDir = "$toolBin".Trim()
}
}
else {
$python = Get-PythonCommand
if ($null -eq $python) {
Fail "Python 3.10 or newer is required when uv is not installed"
Fail "neither uv nor Python 3.10+ was found on PATH." @(
"Install uv from https://docs.astral.sh/uv/getting-started/installation/ (recommended),",
"or install Python 3.10 or newer from https://www.python.org/downloads/, then run this installer again."
)
}

Write-Step "Installing the tocode command with pip"
Expand All @@ -153,18 +219,55 @@ else {
$package = "$InstallDir[dev]"
}
& $python.Name @($python.Args) -m pip install --user --editable $package
Assert-NativeSuccess "pip could not install ToCode"

# The per-user scripts directory is versioned on Windows (for example
# %APPDATA%\Python\Python312\Scripts), so ask Python for the real path
# instead of assuming USER_BASE\Scripts.
$scriptsDir = Invoke-Quiet { & $python.Name @($python.Args) -c "import sysconfig; print(sysconfig.get_path('scripts', sysconfig.get_preferred_scheme('user')))" }
if ($LASTEXITCODE -eq 0 -and $scriptsDir) {
$binDir = "$scriptsDir".Trim()
}
}

if ($binDir) {
Add-UserPath -BinDir $binDir
}

if (Test-Command "tocode") {
tocode --help | Out-Null
Assert-NativeSuccess "tocode is installed but 'tocode --help' failed" @(
"Check the output above, or re-run this installer."
)

$userBase = (& $python.Name @($python.Args) -c "import site; print(site.USER_BASE)")
if ($LASTEXITCODE -eq 0 -and $userBase) {
Add-UserPath -BinDir (Join-Path $userBase 'Scripts')
Write-Host ""
Write-Host "ToCode is installed." -ForegroundColor Green
if ($script:PathWasUpdated) {
Write-Host "Your PATH was updated for future sessions. If 'tocode' is not recognized in an already-open terminal, open a new one."
}
Write-Host "Run: tocode <binary> -o <output_dir>"
exit 0
}

if (-not (Test-Command "tocode")) {
Fail "tocode was installed, but its bin directory is not on PATH"
$tocodeExe = $null
if ($binDir) {
$tocodeExe = Join-Path $binDir "tocode.exe"
}

tocode --help | Out-Null
if ($tocodeExe -and (Test-Path $tocodeExe)) {
Write-Host ""
Write-Host "ToCode is installed." -ForegroundColor Green
Write-Host "The tocode command lives in $binDir, which was added to your PATH, but this terminal does not pick up the change automatically."
Write-Host "Open a new PowerShell window, then run: tocode <binary> -o <output_dir>"
exit 0
}

Write-Step "ToCode is installed"
Write-Host "Run: tocode <binary> -o <output_dir>"
$hints = @()
if ($binDir) {
$hints += "Expected it in $binDir - check that directory and add it to your PATH if it is there."
}
else {
$hints += "Could not determine the tool bin directory. Add the directory containing tocode.exe to your PATH manually."
}
$hints += "You can also run ToCode without PATH changes: uv --directory $InstallDir run tocode --help"
Fail "the install finished, but the tocode command could not be located." $hints
53 changes: 39 additions & 14 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set -euo pipefail
repo_url="${TOCODE_REPO_URL:-https://github.com/buzzer-re/ToCode.git}"
branch="${TOCODE_BRANCH:-main}"
with_dev=false
tocode_bin_dir=""

script_dir="$(cd "$(dirname "$0")" && pwd)"
if [ -n "${TOCODE_INSTALL_DIR:-}" ]; then
Expand Down Expand Up @@ -35,7 +36,11 @@ info() {
}

die() {
printf 'install.sh: %s\n' "$1" >&2
printf '\nToCode was not installed: %s\n' "$1" >&2
shift
for hint in "$@"; do
printf ' %s\n' "$hint" >&2
done
exit 1
}

Expand Down Expand Up @@ -129,7 +134,8 @@ while [ "$#" -gt 0 ]; do
esac
done

command -v git >/dev/null 2>&1 || die "git is required but was not found on PATH"
command -v git >/dev/null 2>&1 || die "git was not found on PATH" \
"Install it with your package manager (for example: apt install git, brew install git), then run this installer again."

if [ -d "$install_dir/.git" ]; then
if [ "$install_dir" = "$script_dir" ]; then
Expand All @@ -141,7 +147,8 @@ if [ -d "$install_dir/.git" ]; then
git -C "$install_dir" pull --ff-only origin "$branch"
fi
elif [ -e "$install_dir" ]; then
die "$install_dir already exists and is not a Git checkout"
die "$install_dir already exists and is not a ToCode Git checkout" \
"Move or delete it, or pick another location with: ./install.sh --dir PATH"
else
info "Cloning ToCode into $install_dir"
git clone --branch "$branch" "$repo_url" "$install_dir"
Expand All @@ -158,16 +165,20 @@ if command -v uv >/dev/null 2>&1; then
info "Installing the tocode command with uv"
uv tool install --force --editable "$install_dir"

tocode_bin_dir="$(uv tool dir --bin 2>/dev/null || true)"
if ! command -v tocode >/dev/null 2>&1; then
tool_bin="$(uv tool dir --bin 2>/dev/null || true)"
ensure_path "$tool_bin"
ensure_path "$tocode_bin_dir"
fi
else
python_bin="$(find_python || true)"
[ -n "$python_bin" ] || die "Python 3.10 or newer is required when uv is not installed"
[ -n "$python_bin" ] || die "neither uv nor Python 3.10+ was found on PATH" \
"Install uv from https://docs.astral.sh/uv/getting-started/installation/ (recommended)," \
"or install Python 3.10 or newer, then run this installer again."

"$python_bin" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)' \
|| die "Python 3.10 or newer is required"
|| die "$python_bin is older than Python 3.10" \
"Install uv from https://docs.astral.sh/uv/getting-started/installation/ (recommended)," \
"or install Python 3.10 or newer, then run this installer again."

info "Installing the tocode command with pip"
if [ "$with_dev" = true ]; then
Expand All @@ -176,12 +187,26 @@ else
"$python_bin" -m pip install --user --editable "$install_dir"
fi

user_bin="$("$python_bin" -c 'import os, site; print(os.path.join(site.USER_BASE, "bin"))')"
ensure_path "$user_bin"
tocode_bin_dir="$("$python_bin" -c 'import sysconfig; print(sysconfig.get_path("scripts", sysconfig.get_preferred_scheme("user")))' 2>/dev/null \
|| "$python_bin" -c 'import os, site; print(os.path.join(site.USER_BASE, "bin"))')"
ensure_path "$tocode_bin_dir"
fi

command -v tocode >/dev/null 2>&1 || die "tocode was installed, but its bin directory is not on PATH"
tocode --help >/dev/null

info "ToCode is installed"
printf 'Run: tocode <binary> -o <output_dir>\n'
if command -v tocode >/dev/null 2>&1; then
tocode --help >/dev/null \
|| die "tocode is installed but 'tocode --help' failed" \
"Check the output above, or run this installer again."
info "ToCode is installed"
printf 'Run: tocode <binary> -o <output_dir>\n'
elif [ -n "$tocode_bin_dir" ] && [ -x "$tocode_bin_dir/tocode" ]; then
info "ToCode is installed"
printf 'The tocode command lives in %s, which is not visible in this shell yet.\n' "$tocode_bin_dir"
printf 'Open a new shell session (or run: source %s), then run: tocode <binary> -o <output_dir>\n' "$(shell_rc_file)"
else
if [ -n "$tocode_bin_dir" ]; then
die "the install finished, but the tocode command could not be located" \
"Expected it in $tocode_bin_dir - check that directory and add it to your PATH if it is there."
fi
die "the install finished, but the tocode command could not be located" \
"Add the directory containing the tocode command to your PATH manually."
fi
Loading