Skip to content

About

Debian packaging and build scripts for Notolog Editor (.deb builder repo)

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Repository files navigation

Debian Package Builder for Notolog Editor

GitHub Release GitHub License GitHub Actions Workflow Status

An isolated build repository for generating .deb packages for Notolog Editor - a Python-powered Markdown editor featuring an integrated AI assistant, on-device LLM support, and optional file encryption.

▒█▄░▒█ ▒█▀▀▀▄ ▀▀█▀▀ ▒█▀▀▀▄ ▒█░░░ ▒█▀▀▀▄ ▒█▀▀█░
▒█▒█▒█ ▒█░░▒█ ░▒█░░ ▒█░░▒█ ▒█░░░ ▒█░░▒█ ▒█░░▄▄
▒█░░▀█ ▒█▄▄▄█ ░▒█░░ ▒█▄▄▄█ ▒█▄▄▄ ▒█▄▄▄█ ▒█▄▄▄█

This repo contains build scripts, CI/CD workflows, and Debian packaging files used to create and lint compliant .deb packages. It does not include application source code.

Installation

For Users: Install from PPA

The easiest way to install Notolog on Ubuntu:

# Add the PPA repository
sudo add-apt-repository ppa:notolog/ppa
sudo apt update

# Install Notolog
sudo apt install notolog

# Run
notolog

The amd64 PPA workflow targets Jammy (22.04 LTS), Noble (24.04 LTS), and Resolute (26.04 LTS). Its default all selection builds one application executable and one shared upstream source archive, then creates the three series-specific source packages using sortable ~ppa1~ubuntu22.04.1-style versions. If the PPA already accepted that upstream version, the workflow downloads its original archive, verifies its SHA-256 checksum and application source against the pinned release, and reuses its executable. Pending uploads count as accepted, even before an APT index is published. The workflow skips source-package versions already registered in the PPA and prepares only the missing ones. Selecting an individual series uses the same archive as all. Uploads reference an already accepted upstream archive without transferring it again; the source artifact still retains that archive for verification and recovery.

A dry run checks source packaging without signing or uploading. A new upstream version also runs the complete application build and bundle checks; an existing version reuses the accepted build. The configured Launchpad owner and PPA must be available for both modes so the workflow can check for an existing archive.

GitHub release builds are native for each architecture: amd64 is built on Ubuntu 22.04 and targets Ubuntu 22.04 or newer; arm64 is built on Ubuntu 24.04 and targets Ubuntu 24.04 or newer. The PPA remains an amd64-only binary-repack workflow because its source upload carries the architecture-specific PyInstaller executable produced by the Ubuntu 22.04 workflow runner. Launchpad rebuilds the Debian package around that executable; it does not recompile the application. GitHub's native release builds are the authoritative standalone package artifacts.


For Developers: Building from Source

Note: The Git repository does not commit generated application binaries or third-party runtime packages. Release builds bundle their dependencies and record the corresponding licence information in the generated package.

System Build Packages

Essential packages required to perform the build:

sudo apt-get install build-essential zlib1g-dev debhelper devscripts lintian libegl1 libportaudio2

Python

Release builds use Python 3.14.10 or a newer Python 3.14 maintenance release with venv support. The build preflight also accepts patched stable Python 3.11–3.13; select another interpreter with PYTHON_BIN. The selected application's dependency requirements and all native compatibility and package checks still apply. The patch-level minimums follow the upstream security releases.

build.sh creates a builder-owned virtual environment and installs the pinned PyInstaller and Python build tools; do not install a separate global PyInstaller for this workflow. Release builds pin the llama-cpp-python version used by the runtime-backend adapter so rebuilding a builder tag cannot silently select a different native ABI.

Building

Using a Builder Script (preferred)

Clone the matching application release into src/, then run the builder from the repository root:

git clone --depth 1 --branch v1.2.4 https://github.com/notolog/notolog-editor.git src
./pyinstaller/build.sh

llama.cpp CPU profiles

The default auto profile uses runtime-dispatched llama.cpp CPU backends on amd64 and a portable backend on arm64, where compiling every backend variant would make release builds substantially slower. On amd64, llama.cpp selects the best backend supported by the current processor at startup, allowing one package to retain the ordinary architecture baseline while using F16C, AVX2, and newer instruction sets where available.

For a smaller generic build without runtime-dispatched backends:

LLAMA_CPU_PROFILE=portable ./pyinstaller/build.sh

The f16c profile enables hardware-accelerated half-precision conversions and can substantially improve llama.cpp CPU inference on compatible amd64 processors:

grep -m1 -w f16c /proc/cpuinfo
LLAMA_CPU_PROFILE=f16c ./pyinstaller/build.sh

The build host and every system running an f16c build must support F16C. The script verifies the build host automatically. Prefer auto for distributed packages; use runtime, portable, or f16c only for controlled builds with specific performance, size, or hardware requirements.

Release tags

Application and builder tags have different purposes:

  • notolog-editor uses the upstream application tag, for example v1.2.4.
  • notolog-debian uses the full Debian version, for example v1.2.4-1ubuntu1.

The builder workflow requires its release tag to equal the version in debian/changelog. The application source must declare the matching upstream version in pyproject.toml; builder tag v1.2.4-1ubuntu1 therefore packages application version 1.2.4. Create the builder tag only after the matching application release is public and the builder's Launchpad dry run succeeds.

For a release:

  1. Run the Upload to Launchpad PPA workflow from the release commit with version_override set to the application tag, ubuntu_series set to all, ppa_revision set to 1, and dry_run enabled.
  2. Review the generated source-package artifact and confirm that all source, lint, bundle, frozen-module, GUI smoke, architecture, glibc, and hardening checks pass.
  3. Create and push the signed builder tag using the full Debian version.
  4. Run the same Launchpad workflow with dry_run disabled. Check acceptance for each selected series after transfer. Launchpad's binary builds may remain queued independently of the upload workflow.

Each source-package version and upstream archive is immutable. To update Debian packaging, increase the Debian revision or ppa_revision; the workflow still reuses the accepted upstream archive. Replacing the application executable or upstream contents requires a new upstream version. Do not move a published tag.

If an upload stops after one series succeeds, rerun with the same application version and ppa_revision, choosing all or a missing series. Accepted versions are skipped, and missing versions reference the original archive already held by Launchpad. Increasing ppa_revision alone cannot resolve a conflicting .orig.tar.xz: the archive belongs to the upstream version, not the series or Debian revision. Transfer retries resend the same signed files. Source artifacts are retained before upload for recovery. Check Launchpad's acceptance and build status separately from the workflow's transfer result.

To remove builder-owned generated artifacts:

./pyinstaller/clean-build.sh

Built Package Installation

The built package can be installed with the command below.

sudo apt install ../notolog_X.Y.Z-REVISION_ARCH.deb

If the package was built on a local machine, the resulting .deb file is typically located in the parent directory (..) relative to where the debian/ directory resides.

PyInstaller spec file

pyinstaller/notolog-onefile.spec is the authoritative standalone-binary definition. Use ./pyinstaller/build.sh so the native bootloader, llama.cpp library, dependency audit, license report, and Debian package are produced consistently.

PyInstaller Init Script

The init script pyinstaller/runtime_hooks/init.py configures the app on first run based on user settings and package type. It verifies the current package type and adjusts settings accordingly.

Possible Issues

Qt Platform Plugin (xcb) Error

If you see:

qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: linuxfb, minimalegl, xcb, minimal, vkkhrdisplay, wayland, vnc, offscreen, wayland-egl, eglfs.

Aborted (core dumped)

Install the required package:

sudo apt-get install libxcb-cursor0

Linter

REUSE-compliance Tools:

Install REUSE

pip install reuse

Fetch missing licenses

# Download all SPDX-referenced licenses
reuse download --all
# Or download a specific license and place it in the LICENSES/ directory
reuse download PSF-2.0

Run REUSE linting

reuse lint

Annotate specific files

reuse annotate --copyright="2024-2026 Author Name" \
  --license="MIT" --skip-unrecognised \
  debian/README.md debian/changelog debian/control

Check .deb File

Lint the built .deb package:

sudo apt-get install -y lintian
lintian notolog.deb

For detailed output and to help debug any issues, use the --info flag:

lintian -i notolog.deb
# Or, for even more verbose output:
lintian -iIv notolog.deb

Check PIE

PIE (Position Independent Executable) hardening ensures that the binary can be loaded at a random memory address each time it runs.

This enhances security by enabling ASLR (Address Space Layout Randomization), which protects against memory corruption attacks like buffer overflows.

For .deb packages, this is a Debian security best practice and is checked by tools like lintian.

Verify PIE status

After building, run:

hardening-check pyinstaller/dist/notolog
# Or, if the app is already installed:
hardening-check /usr/bin/notolog

You want to see:

Position Independent Executable: yes

Or, to check manually with readelf:

readelf -h /usr/bin/notolog | grep 'Type'

Expected output:

Type: DYN (Position-Independent Executable)

Validate .desktop File

Run this to validate:

desktop-file-validate /usr/share/applications/notolog.desktop

Validate man Page

dpkg-deb -c notolog_*.deb | grep 'man/man1'

The output should be:

./usr/share/man/man1/notolog.1.gz

Then check the man entry:

man notolog

Licensing & Dependency Inspection

Use these steps to verify what's bundled into the PyInstaller binary - important for compliance, reproducibility, and Debian policy alignment.

Confirm What's Inside

Inspect .deb contents:

dpkg-deb -c notolog_*.deb

PyInstaller one-file packages store shared objects inside the executable archive, so they do not appear as separate files in dpkg-deb -c output.

If using a --onefile PyInstaller build, run the app once to trigger runtime extraction. Then inspect with:

ps aux | grep notolog
lsof -p $(pgrep notolog) | grep _MEI
# The default extraction directory is a private, per-process _MEI directory
# under the user's secure temporary directory.

Optional: Use strace if you need syscall-level info:

strace -f -e trace=openat /usr/bin/notolog

Note: strace is a syscall tracer. It works by launching (or attaching to) the process and intercepting all syscalls (like openat, read, etc.). This means it will run the app while tracing - that's expected behavior.

See linked shared libraries:

ldd /usr/bin/notolog

Check which Debian package provides a library:

dpkg -S libexpat.so.1
# or
apt show libexpat1
# and
cat /usr/share/doc/libexpat1/copyright

To inspect the contents of a PyInstaller executable (ensure the virtual environment is activated):

pyi-archive_viewer pyinstaller/dist/notolog

Inside the viewer shell:

> ls
> extract libexpat.so.1

Check llama-cpp Runtime Linking

To confirm libllama.so and its dependencies are dynamically linked and runtime-bundled:

RUNTIME_DIR=$(lsof -p "$(pgrep -n notolog)" | awk '/_MEI/ {print $9; exit}')
find "$RUNTIME_DIR" -path '*llama_cpp*' -name 'libllama.so' -exec ldd {} \;

License Check

To verify bundled binaries for license metadata, use licensecheck:

licensecheck --shortname-scheme new --recursive "$RUNTIME_DIR"

RUNTIME_DIR is discovered from the running process because PyInstaller creates a private randomized extraction directory for every launch.

The --shortname-scheme new flag ensures SPDX-style identifiers (e.g. mit, lgpl-2.1+, etc.).

This is especially useful for auditing libraries bundled in --onefile PyInstaller builds.

CI/CD workflows

The build process is automated using GitHub Actions, and the resulting artifact is uploaded after the workflow completes.

Refer to .github/workflows/build.yaml for details and step-by-step instructions.

Contributing

See CONTRIBUTING.md for guidelines.

Licensing

This repository contains only build scripts and CI workflows. It does not include or redistribute any third-party software.

All third-party dependencies are pulled by the main application during build and bundled into the final .deb as part of the PyInstaller runtime. Licensing for each is tracked and included in the package metadata.

🦙 The CPU-only llama-cpp backend is built from source and dynamically links to:

  • libgomp and libstdc++: covered under the GPL with the GCC Runtime Library Exception, which permits linking from non-GPL software.
  • MIT-licensed internal libggml backends (libggml.so, libggml-base.so, and the selected libggml-cpu-*.so variant).

About

Debian packaging and build scripts for Notolog Editor (.deb builder repo)

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages