windows/python-gtk3-install.ps1
Rama master · réplica de lectura del repositorio original.
<#
Install Python and GTK development and build environment for BleachBit on Windows.
This is a special version built for BleachBit.
It installs in a portable style.
This script may be run in an empty directory like `c:\projects`.
Afterwards, launch the application like this:
c:\projects\x86-windows\tools\python3\python.exe c:\projects\bleachbit\bleachbit.py
This assumes that the BleachBit source code is in `c:\projects\bleachbit` and PyGTK
is installed in `c:\projects\pygtk`, but either directory can be relocated.
Copyright (C) 2008-2025 Andrew Ziem
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
#>
# CI's pwsh wrapper already does this, but `powershell -File` does not
$ErrorActionPreference = 'Stop'
$root_dir = Join-Path (Get-Location).Path "vcpkg_installed\x86-windows"
$python_home = Join-Path $root_dir "tools\python3"
$themes_dir = Join-Path $python_home "share\themes"
# When the tree is restored from cache python.exe already exists, so the pip
# bootstrap and installs below can be skipped. A dependency change busts the
# cache key, forcing a fresh unpack where this is false.
$python_exists = Test-Path "$python_home\python.exe"
# location of this .ps1 script
$script_dir = Split-Path -Parent $MyInvocation.MyCommand.Path
$base_download_url = "https://github.com/bleachbit/pygtkwin/releases/download/v2026-10-13/"
function Assert-FileHash($Path, $Expected) {
$actual = (Get-FileHash -Path $Path -Algorithm SHA256).Hash
if ($actual -ine $Expected) {
throw "SHA256 mismatch for ${Path}: expected $Expected, got $actual"
}
}
function Expand-7z($Path) {
$seven_zip = (Get-Command 7z.exe -ErrorAction SilentlyContinue).Source
if (-not $seven_zip) {
$seven_zip = Join-Path $env:ProgramFiles "7-Zip\7z.exe"
}
if (-not (Test-Path $seven_zip)) {
Write-Error "7-Zip is needed to unpack $Path"
exit 1
}
& $seven_zip x -bso0 -bsp0 -y $Path
if ($LASTEXITCODE -ne 0) {
Write-Error "7-Zip failed to unpack ${Path}: exit code $LASTEXITCODE"
exit $LASTEXITCODE
}
}
# Visual C++ Redistributable 2015 x86
$VC_REDIST_FN = "VC_redist.x86.exe"
$VC_REDIST_URL = "https://aka.ms/vs/17/release/vc_redist.x86.exe"
if (-not $env:GITHUB_ACTIONS) {
if (-not (Test-Path $VC_REDIST_FN)) {
Write-Host "Downloading Visual C++ Redistributable..."
Invoke-WebRequest -Uri $VC_REDIST_URL -OutFile $VC_REDIST_FN
Get-FileHash -Path $VC_REDIST_FN -Algorithm SHA256 | Format-List
$fileSizeMB = (Get-Item $VC_REDIST_FN).Length / 1MB
if ($fileSizeMB -lt 5) {
Write-Warning "The downloaded Visual C++ Redistributable file is smaller than expected (< 5MB). Please verify its integrity."
}
} else {
Write-Host "Visual C++ Redistributable is already downloaded."
}
if (-not (Test-Path "C:\Windows\SysWOW64\vcruntime140.dll")) {
Write-Host "Installing Visual C++ Redistributable..."
Write-Host "Tip: If this step seems to freeze, press ALT+TAB to check for the UAC dialog."
Start-Process -FilePath $VC_REDIST_FN -ArgumentList "/install", "/quiet", "/norestart" -Wait
} else {
Write-Host "Visual C++ Redistributable is already installed."
}
} else {
Write-Host "Skipping Visual C++ Redistributable installation in CI."
}
# Python and GTK+
$GTK_ARCHIVE_FN = "gtk3.24-x86-windows.7z"
if (-not (Test-Path $GTK_ARCHIVE_FN)) {
Write-Host "Downloading Python and GTK+..."
Invoke-WebRequest -Uri "$base_download_url/$GTK_ARCHIVE_FN" -OutFile $GTK_ARCHIVE_FN
} else {
Write-Host "Python and GTK+ are already downloaded."
}
Assert-FileHash $GTK_ARCHIVE_FN "d3fd28959ab69ceb185a3f22cfe03bd6f00ab4f7e896621b850e377913a992f3"
if (-not (Test-Path $python_home\python.exe)) {
Write-Host "Unpacking Python and GTK+..."
Expand-7z $GTK_ARCHIVE_FN
} else {
Write-Host "Python and GTK+ are already unpacked."
}
if (-not (Test-Path "$root_dir\tools\gtk3\gtk-launch.exe")) {
Write-Error "GTK+ is not installed correctly."
exit 1
}
$schema_compiler = Join-Path $root_dir "tools\glib\glib-compile-schemas.exe"
$schema_dir = Join-Path $root_dir "share\glib-2.0\schemas"
if (-not (Test-Path "$schema_dir\gschemas.compiled")) {
Write-Host "Compiling GLib schemas..."
& $schema_compiler $schema_dir
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to compile GLib schemas: exit code $LASTEXITCODE"
exit $LASTEXITCODE
}
if (-not (Test-Path "$schema_dir\gschemas.compiled")) {
Write-Error "Failed to compile GLib schemas: $schema_dir\gschemas.compiled does not exist"
exit 1
}
}
# This fixes the chaff dialog when running on Windows from source.
New-Item -ItemType Directory -Path "$python_home\share\glib-2.0\schemas" -Force
Copy-Item -Path "$schema_dir\gschemas.compiled" -Destination "$python_home\share\glib-2.0\schemas" -Force
Write-Host "Checking Python version"
& "$python_home\python.exe" -V # show Python version
if ($LASTEXITCODE -ne 0) {
Write-Error "python.exe -V failed"
exit $LASTEXITCODE
}
# Add Python home and scripts to PATH.
if ($env:PATH -notlike "*$python_home*") {
Write-Host "Adding Python home and scripts to PATH..."
$env:PATH += ";$python_home;$python_home\Scripts"
Write-Host "Updated PATH: $env:PATH"
}
if (-not $python_exists) {
Write-Host "ensurepip"
& "$python_home\python.exe" -m ensurepip
Write-Host "Checking pip version"
& "$python_home\Scripts\pip3.exe" --version # show pip version
Write-Host "Updating pip..."
& "$python_home\python.exe" -m pip install --disable-pip-version-check --upgrade pip
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to update pip: exit code $LASTEXITCODE"
exit $LASTEXITCODE
}
} else {
Write-Host "Python is already unpacked; skipping pip bootstrap."
}
if (-not (Test-Path gtk-themes.zip)) {
Write-Host "Downloading GTK themes..."
#Invoke-WebRequest -Uri "$base_download_url/gtk-themes.zip" -OutFile "gtk-themes.zip"
#FIXME: use new themes
Invoke-WebRequest -Uri "https://github.com/mkhon/vcpkg/releases/download/gtk3-introspection-v1/gtk-themes.zip" -OutFile "gtk-themes.zip"
} else {
Write-Host "GTK themes are already downloaded."
}
Assert-FileHash gtk-themes.zip "6BD572256773175C0139FCA9AD0D28A0EF23B4E087901D04198FF907FC096624"
if (-not (Test-Path "$themes_dir")) {
Write-Host "Unpacking GTK themes..."
Expand-Archive -Path gtk-themes.zip -DestinationPath .
Copy-Item -Path "gtk-themes\*" -Destination $python_home -Recurse -ErrorAction SilentlyContinue
} else {
Write-Host "GTK themes are already unpacked."
}
if (-not (Test-Path "$themes_dir\Adwaita\index.theme")) {
Write-Error "GTK themes are not installed correctly."
exit 1
}
if (Test-Path "gtk-themes") {
Write-Host "Removing temporary directory gtk-themes..."
Remove-Item -Path "gtk-themes" -Recurse
}
# psutil 7.1.2 stopped providing 32-bit wheels.
# It needs MSVC++ with the python3.lib.
Write-Host "Copying python312.lib..."
New-Item -ItemType Directory -Path "$python_home\libs" -Force
$pylibdest = "$python_home\libs\python3.lib"
Copy-Item -Path "$root_dir\lib\python312.lib" -Destination $pylibdest
Get-ChildItem -Path $pylibdest | Format-List -Property Name, Length
# Install pip packages
if (-not $python_exists) {
Write-Host "pip install -r requirements.txt..."
& "$python_home\Scripts\pip3.exe" install --disable-pip-version-check -r "$script_dir\requirements.txt"
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to update pip: exit code $LASTEXITCODE"
exit $LASTEXITCODE
}
}
$PYGOBJECT_FN = "pygobject-3.58.0-cp312-cp312-win32.whl"
if (-not (Test-Path $PYGOBJECT_FN)) {
Write-Host "Downloading PyGObject..."
Invoke-WebRequest -Uri "$base_download_url/$PYGOBJECT_FN" -OutFile "$PYGOBJECT_FN"
} else {
Write-Host "PyGObject is already downloaded."
}
Assert-FileHash $PYGOBJECT_FN "a51a6fa9b1cbe55485d63c08e953538c72007a3798fc2285ca369625a0265f29"
if (-not $python_exists) {
Write-Host "pip install $PYGOBJECT_FN..."
& "$python_home\Scripts\pip3.exe" install --disable-pip-version-check $PYGOBJECT_FN
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to install PyGObject: exit code $LASTEXITCODE"
exit $LASTEXITCODE
}
}
# By default, pygobject installs to `x86-windows\lib\girepository-1.0`.
# Copy it to `x86-windows\tools\python3\lib\girepository-1.0`.
$girepo_dir = "$python_home\lib\girepository-1.0"
if (-not (Test-Path $girepo_dir)) {
New-Item -Path "$girepo_dir" -ItemType Directory -Force
Copy-Item -Path "$root_dir\lib\girepository-1.0\*" -Destination "$girepo_dir" -Recurse -Force -ErrorAction Stop
}
# Copy GTK dependencies to Python home.
Get-Content "$script_dir\python-gtk3-deps.lst" | ForEach-Object {
Write-Host "Copying $_..."
if (-not (Test-Path "$python_home\$_")) {
Copy-Item -Path "$root_dir\$_" -Destination "$python_home" -Recurse -Force
}
}
Write-Host "Copying gdk-pixbuf-2.0..."
$GDK_PIXBUF_DIR = "$python_home\lib\gdk-pixbuf-2.0\2.10.0"
if (-not (Test-Path $GDK_PIXBUF_DIR)) {
Write-Host "Creating $GDK_PIXBUF_DIR..."
New-Item -Path $GDK_PIXBUF_DIR -ItemType Directory -Force
}
$GDK_PIXBUF_LOADER_DIR = Join-Path $GDK_PIXBUF_DIR "loaders"
if (-not (Test-Path $GDK_PIXBUF_LOADER_DIR)) {
New-Item -Path $GDK_PIXBUF_LOADER_DIR -ItemType Directory -Force | Out-Null
}
$svg_loader_src = Join-Path $root_dir "lib\gdk-pixbuf-2.0\2.10.0\loaders\pixbufloader-svg.dll"
if (Test-Path $svg_loader_src) {
Copy-Item -Path $svg_loader_src -Destination $GDK_PIXBUF_LOADER_DIR -Force
}
Get-ChildItem -Path $GDK_PIXBUF_LOADER_DIR | Format-List -Property Name, Length
# Update cache file for GDK pixbuf.
$env:GDK_PIXBUF_MODULE_FILE = "$GDK_PIXBUF_DIR\loaders.cache"
if (-not (Test-Path $env:GDK_PIXBUF_MODULE_FILE)) {
Write-Host "Creating $env:GDK_PIXBUF_MODULE_FILE..."
$prevPath = $env:PATH
try {
$env:GDK_PIXBUF_MODULEDIR = $GDK_PIXBUF_LOADER_DIR
$env:PATH = "$python_home\bin;$python_home;$python_home\Scripts;$root_dir\tools\gtk3;$prevPath"
& "$root_dir\tools\gdk-pixbuf\gdk-pixbuf-query-loaders.exe" --update-cache
if ($LASTEXITCODE -ne 0) {
Write-Error "gdk-pixbuf-query-loaders.exe failed with exit code $LASTEXITCODE"
exit $LASTEXITCODE
}
} finally {
$env:PATH = $prevPath
}
}