Skip to content
Open
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ MANIFEST
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec


# Installer logs
pip-log.txt
Expand Down
62 changes: 46 additions & 16 deletions spsvalidator/packaging/build_linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,49 @@ set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"

python -m pip install -e ".[dev]"
python -m pip install pyinstaller
pyinstaller --noconfirm --windowed \
--name spsvalidator \
--icon src/spsvalidator/web/static/img/icon.png \
--paths src \
--collect-all packtools \
--collect-all webview \
--collect-data spsvalidator \
--hidden-import pkg_resources \
--hidden-import requests \
--hidden-import tenacity \
--hidden-import langdetect \
--copy-metadata setuptools \
src/spsvalidator/main.py
echo "Use linuxdeploy/appimagetool to convert dist/spsvalidator into AppImage."
SPEC_FILE="${ROOT_DIR}/src/spsvalidator/spsvalidator_linux.spec"

VENV_DIR="${ROOT_DIR}/.venv"
_ensure_build_venv() {
if [[ -d "$VENV_DIR" ]] && ! "$VENV_DIR/bin/python" -c "import gi" >/dev/null 2>&1; then
rm -rf "$VENV_DIR"
fi
if [[ ! -d "$VENV_DIR" ]]; then
python3 -m venv --system-site-packages "$VENV_DIR"

@pitangainnovare pitangainnovare Jun 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Se a pessoa possuir o miniconda ou o conda ou outro framework que encapula versões de python, esse código usa o python desse framewor, que não enxerga os pacotes instalados no sistema. E por causa disso, ocorre o erro de Missing GTK bindings (gi).

Sugiro adotar o python disponível em /usr/bin/python3 no lugar desse python3 (que pode ser um atalho para outro python qualquer, inclusive do conda).

Veja o erro persistindo memos após a instalação das deps:

Image

Veja como pode ser resolvido usando o SYSTEM_PYTHON (apenas mudar a linha que chama python3 é o suficiente - para /usr/bin/python3):

#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"

VENV_DIR="${ROOT_DIR}/.venv"
SYSTEM_PYTHON="/usr/bin/python3"

_ensure_build_venv() {
  if [[ -d "$VENV_DIR" ]] && ! "$VENV_DIR/bin/python" -c "import gi" >/dev/null 2>&1; then
    echo "Existing venv cannot import gi. Recreating with system-site-packages..."
    rm -rf "$VENV_DIR"
  fi

  if [[ ! -d "$VENV_DIR" ]]; then
    "$SYSTEM_PYTHON" -m venv --system-site-packages "$VENV_DIR"
  fi
}

# Always use this build venv, even if another venv/conda is active.
_ensure_build_venv

# shellcheck source=/dev/null
source "$VENV_DIR/bin/activate"

echo "Using Python: $(python -c 'import sys; print(sys.executable)')"

if ! python -c "import gi" >/dev/null 2>&1; then
  echo "Missing GTK bindings (gi). Install system packages and rebuild:" >&2
  echo "  sudo apt install python3-gi python3-gi-cairo gir1.2-webkit-6.0" >&2
  echo "Also check: /usr/bin/python3 -c 'import gi'" >&2
  exit 1
fi

python -m pip install -U pip
python -m pip install -e .
python -m pip install pyinstaller

rm -rf build/spsvalidator dist/spsvalidator spsvalidator.spec

pyinstaller --noconfirm --clean --onefile --windowed \
  --name spsvalidator \
  --icon src/spsvalidator/web/static/img/icon.png \
  --paths src \
  --collect-data packtools \
  --collect-data spsvalidator \
  --hidden-import pkg_resources \
  --hidden-import requests \
  --hidden-import tenacity \
  --hidden-import langdetect \
  --hidden-import gi \
  --hidden-import gi.repository \
  --hidden-import gi.repository.Gtk \
  --hidden-import gi.repository.WebKit2 \
  --hidden-import webview.platforms.gtk \
  --exclude-module webview.platforms.qt \
  --exclude-module webview.platforms.android \
  --exclude-module webview.platforms.cocoa \
  --exclude-module webview.platforms.winforms \
  --exclude-module webview.platforms.edgechromium \
  --exclude-module qtpy \
  --exclude-module PyQt6 \
  --exclude-module PySide6 \
  --exclude-module black \
  --exclude-module pytest \
  --exclude-module isort \
  --copy-metadata setuptools \
  src/spsvalidator/main.py

echo "Linux executable generated at dist/spsvalidator."
echo "Use linuxdeploy/appimagetool to convert it into AppImage."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E ao rodar o spspackage gerado, obtive erro por falta de biblioteca.

image

Pode ser importante saber qual é o meu sistema para que você rastrei melhor o que faltou:
image

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Esse último foi resolvido instalando gir1.2-webkit2-4.1 via apt install gir1.2-webkit2-4.1. Ainda assim o sistema seguiu acusando ausência de libs. Diria que é preciso tornar o build mais robusto (à prova de KDE e GTK). Ao tentar subir um pacote, o app crashou:

image

Duas opções:

  1. Gerar build linux para gtk e gerar outra build linux para kde.
  2. Aumentar as deps instaladas para garantir bom funcionamento em maior número de IDEs

@samuelveigarangel samuelveigarangel Jun 30, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eu posso inserir uma dependência python no arquivo pyproject.toml para ele utilizar essa dependencia. O que tu acha?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ou eu posso gerar esse arquivo atraves de um docker temporario.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

É uma ótima alternativa.

Garantir que o executável rode corretamente em gtk e qt é importante.

fi
}

if [[ -z "${VIRTUAL_ENV:-}" ]]; then
_ensure_build_venv
# shellcheck source=/dev/null
source "$VENV_DIR/bin/activate"
fi

if ! python -c "import gi" >/dev/null 2>&1; then
echo "Missing GTK bindings (gi). Install system packages and rebuild:" >&2
echo " sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-webkit-6.0" >&2
exit 1
fi

python -m pip install -e .
python -m pip install "pywebview[qt]" pyinstaller

if ! python -c "import webview.platforms.qt" >/dev/null 2>&1; then
echo "Missing Qt backend for pywebview. Install system packages and rebuild:" >&2
echo " sudo apt install python3-pyqt6 python3-pyqt6.qtwebengine" >&2
exit 1
fi

if [[ ! -f "$SPEC_FILE" ]]; then
echo "Spec file not found: $SPEC_FILE" >&2
exit 1
fi

# Remove old output so the binary can use dist/spsvalidator.
rm -rf build/spsvalidator dist/spsvalidator

pyinstaller --noconfirm --clean "$SPEC_FILE"

echo "Linux executable generated at dist/spsvalidator."
echo "GTK and Qt backends are bundled; runtime still needs system GTK or Qt libraries."
echo "Use linuxdeploy/appimagetool to convert it into AppImage."
83 changes: 83 additions & 0 deletions spsvalidator/src/spsvalidator/spsvalidator_linux.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# -*- mode: python ; coding: utf-8 -*-
import os

from PyInstaller.utils.hooks import collect_all, collect_data_files, copy_metadata

project_root = os.path.abspath(os.path.join(SPECPATH, "..", ".."))
main_script = os.path.join(project_root, "src", "spsvalidator", "main.py")
src_path = os.path.join(project_root, "src")
icon_path = os.path.join(
project_root, "src", "spsvalidator", "web", "static", "img", "icon.png"
)

datas = []
binaries = []
hiddenimports = [
"pkg_resources",
"requests",
"tenacity",
"langdetect",
"gi",
"gi.repository",
"gi.repository.Gtk",
"gi.repository.WebKit2",
"webview.platforms.gtk",
"webview.platforms.qt",
]
datas += collect_data_files("packtools")
datas += collect_data_files("spsvalidator")
datas += copy_metadata("setuptools")
tmp_ret = collect_all("webview")
datas += tmp_ret[0]
binaries += tmp_ret[1]
hiddenimports += tmp_ret[2]

a = Analysis(
[main_script],
pathex=[src_path],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
hooksconfig={
"gi": {
"icons": ["hicolor"],
"themes": [],
}
},
runtime_hooks=[],
excludes=[
"webview.platforms.android",
"webview.platforms.cocoa",
"webview.platforms.winforms",
"webview.platforms.edgechromium",
"black",
"pytest",
"isort",
],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)

exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name="spsvalidator",
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=[icon_path],
)