Search
Write a publication
Pull to refresh

Кросс-платформенный Rust от и до: GUI + CLI + CI + Docker Реальный опыт доставки DotPlus на Linux и ARM

Level of difficultyEasy
Reading time15 min
Views2.2K

🔧 Кросс-сборка CLI и GUI-приложения на Rust — проблемы и решения

DotPlus — это Rust-приложение с графическим и консольным интерфейсом. Изначально оно разрабатывалось под Windows, но в планах была сборка под Linux и Docker.

Решение: добавить полноценные Linux-сборки с поддержкой GUI и CLI и обеспечить стабильную доставку под несколько архитектур.

❗ Почему не просто cargo build?

Если хочется стабильную сборку не только под x86_64, но и под ARM (Raspberry Pi, серверы), одной команды cargo build недостаточно. Возникают проблемы:

  • Нужны кросс-компиляторы (gcc-aarch64-linux-gnu и др.)

  • Требуется ручная настройка sysroot, musl, glibc

  • При использовании GUI (через eframe и egui) иногда всплывают платформозависимые проблемы с OpenGL, зависимостями или rfd (файловые диалоги)

🛠 Решение: cross-rs

Чтобы не городить окружения вручную и не писать десятки --target-флагов с настройкой toolchain, я решил использовать cross — это официальный инструмент от сообщества Rust, который:

  • Использует Docker-образы с преднастроенным окружением для каждой архитектуры

  • Упрощает кросс-компиляцию одной командой:

cross build --release --target aarch64-unknown-linux-gnu
  • Работает из коробки как с CLI, так и с GUI (если система сборки внутри контейнера поддерживает нужные dev-пакеты)

⚙️ Конфигурация: cross.toml

Вот пример моего cross.toml, где перечислены поддерживаемые архитектуры:

[target.aarch64-unknown-linux-gnu]
image = "ghcr.io/cross-rs/aarch64-unknown-linux-gnu:edge"

[target.armv7-unknown-linux-gnueabihf]
image = "ghcr.io/cross-rs/armv7-unknown-linux-gnueabihf:edge"

[target.x86_64-unknown-linux-gnu]
image = "ghcr.io/cross-rs/x86_64-unknown-linux-gnu:edge"

Образы edge — это свежие контейнеры с последними версиями компилятора и зависимостей. Именно они обеспечивают корректную сборку egui, eframe и rfd в Linux-окружении.

🧱 GUI + CLI: архитектура фич

[features]
default = ["gui"]
gui = ["eframe", "egui", "rfd", "egui_extras"]
notifications = ["notify-rust"]

Благодаря этому:

  • Сборка CLI-версии возможна без GUI (--no-default-features)

  • На Linux можно собирать оба варианта одновременно, включая полноценное GTK/Wayland GUI через eframe

Такой подход оказался крайне удобным: в одном проекте можно выпускать и headless-бинарник, и полноценное графическое приложение.

🪓 От чего пришлось отказаться

Несмотря на успех с cross, не обошлось без потерь:

  • musl-сборки (статически линкуемые) были отброшены — eframe и rfd плохо работают в таком окружении

  • Windows ARM MIPS и прочие экзотические платформы — слишком нестабильны и слабо поддерживаются в cross

  • Слишком "чистая" сборка без Docker — пришлось отказаться от идеи собирать без контейнеров, так как зависимостей GUI слишком много, и они не всегда есть на GitHub Actions runner'ах

✅ Что в итоге получилось

В результате, с помощью cross теперь собираются полноценные GUI+CLI бинарники под Linux для трёх платформ:

Архитектура

Поддержка

Назначение

x86_64-unknown-linux-gnu

✅ GUI/CLI

Десктопы и серверы

aarch64-unknown-linux-gnu

✅ GUI/CLI

ARM64 серверы, RPi 4 и новее

armv7-unknown-linux-gnueabihf

✅ GUI/CLI

RPi 3 и другие ARMv7 SBC

✅ Итог: благодаря cross

DotPlus теперь полноценно работает на Linux с графическим интерфейсом и CLI. Одинаковый UX, стабильные сборки, возможность использовать на Raspberry Pi и сервере — всё это стало реальностью.

🚀 CI/CD: автоматизация сборки, кросс-компиляции и релизов

После успешной настройки cross для локальной кросс-компиляции стало ясно: ручной процесс не масштабируется. Хотелось воспроизводимой, полностью автоматизированной системы, которая при любом обновлении могла бы:

  • Собрать DotPlus под несколько архитектур

  • Подготовить установочные пакеты .deb и .rpm

  • Собрать и опубликовать Docker-образ

  • Сформировать релиз и прикрепить артефакты

Так родился CI/CD-процесс на базе GitHub Actions, который покрывает весь цикл сборки и доставки.

📂 Общая структура

CI/CD реализован в одном workflow-файле 📄 build-multiarch.yml:

name: Build dotplus (.deb/.rpm) for all architectures

on:
  push:
    branches: [linux]
    tags: ["v*"]
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      CROSS_SKIP_VERSION_CHECK: "1"
    steps:
      - name: 🧾 Checkout
        uses: actions/checkout@v4

      - name: ⚡️ Cache Cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin
            ~/.cargo/registry
            ~/.cargo/git
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-cargo-

      - name: 🧬 Enable QEMU for multi-arch RPM
        uses: docker/setup-qemu-action@v3
        with:
          platforms: all

      - name: 🦀 Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          override: true
          components: rustfmt

      - name: 🎯 Add targets
        run: |
          rustup target add \
            x86_64-unknown-linux-gnu \
            aarch64-unknown-linux-gnu \
            armv7-unknown-linux-gnueabihf

      - name: 🐳 Install Docker & Cross
        run: |
          sudo apt update
          sudo apt install -y docker.io containerd
          if ! command -v cross &>/dev/null; then
            cargo install cross
          else
            echo "✅ cross уже установлен, пропускаем"
          fi

      - name: 📦 Install deb/rpm tools
        run: |
          sudo apt install -y \
            dpkg-dev debhelper rpm rpm2cpio fakeroot \
            qemu-user-static binfmt-support \
            gcc-multilib libc6-dev-i386 pkg-config \
            libssl-dev libstdc++-12-dev

      - name: 🔧 Make script executable
        run: chmod +x tools/generate.sh

      - name: 🛠 Run build script
        run: ./tools/generate.sh

      - name: ☁️ Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dotplus-packages
          path: |
            build/**/dotplus_*.deb
            build/**/RPMS/**/*.rpm

  docker:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: 🧾 Checkout
        uses: actions/checkout@v4

      - name: 🦀 Install Rust + cross
        run: |
          rustup update
          rustup target add x86_64-unknown-linux-musl
          cargo install cross

      - name: 🛠 Build static binary (musl, CLI-only)
        run: cross build --release --target x86_64-unknown-linux-musl --no-default-features

      - name: 🧰 Prepare Docker context
        run: |
          if [[ -f target/x86_64-unknown-linux-musl/release/dotplus ]]; then
            cp target/x86_64-unknown-linux-musl/release/dotplus docker/dotplus
          else
            echo "❌ Static binary not found"
            exit 1
          fi

      - name: 🐳 Build Docker image
        run: docker build -t dotplus-cli -f docker/Dockerfile.cli ./docker

      - name: ☁️ Save Docker image as archive
        run: docker save dotplus-cli | gzip > dotplus-cli.tar.gz

      - name: ☁️ Upload Docker image artifact
        uses: actions/upload-artifact@v4
        with:
          name: dotplus-cli-docker
          path: dotplus-cli.tar.gz

📄 build-multiarch.yml запускается при пуше в ветки release-linux или release-docker и выполняет сборку, упаковку, публикацию и деплой.

⚙️ Этапы пайплайна

Дата: 01.07.2025
Файл Workflow: build-multiarch.yml
Триггер: Push в ветку linux

📦 Этап 1: build (⏱ ~16 минут)

Шаг

Описание

⚙️ Set up job

Инициализация задания

📥 Checkout

Клонирование репозитория

Cache Cargo

Кэширование зависимостей

🧩 Enable QEMU for multi-arch RPM

Эмуляция архитектур

🦀 Install Rust

Установка Rust

🎯 Add targets

Добавление целевых архитектур

🐳 Install Docker & Cross

Установка Docker и cross

🧰 Install deb/rpm tools

Установка сборочных инструментов

🔧 Make script executable

Подготовка сборочного скрипта

▶️ Run build script

Сборка .deb и .rpm

⬆️ Upload artifacts

Загрузка артефактов

♻️ Post-steps

Очистка: откат QEMU, кэша и checkout

📤 Артефакты: .deb, .rpm
📤 Артефакты: .deb, .rpm

🐳 Этап 2: docker (⏱ ~4 минуты)

Шаг

Описание

⚙️ Set up job

Инициализация задания

📥 Checkout

Клонирование репозитория

🦀 Install Rust + cross

Установка Rust + кросс-компиляция

🛠 Build static binary

Сборка статичного бинарника (musl, CLI-only)

🧳 Prepare Docker context

Подготовка контекста для Docker

🔨 Build Docker image

Сборка образа

💾 Save Docker image

Сохранение Docker-образа в архив

⬆️ Upload Docker artifact

Загрузка архива как артефакт

♻️ Post-steps

Очистка: откат checkout

📤 Артефакт: архив Docker-образа
📤 Артефакт: архив Docker-образа
🔄 Общая структура пайплайна
🔄 Общая структура пайплайна

🔄 Кросс-сборка бинарников

Кросс-компиляция происходит с использованием cross, который изолирует сборку в готовых Docker-образах:

- name: Build for aarch64
  run: cross build --release --target aarch64-unknown-linux-gnu

- name: Build for armv7
  run: cross build --release --target armv7-unknown-linux-gnueabihf

- name: Build for x86_64
  run: cross build --release --target x86_64-unknown-linux-gnu

Это гарантирует одинаковые бинарники независимо от среды, включая GUI-часть на Linux.

📦 Пакетирование: .deb и .rpm из CI

  • dotplus_1.0.0_amd64.deb

  • dotplus_1.0.0_arm64.deb

  • dotplus_1.0.0_armhf.deb

  • dotplus-1.0.0-1.x86_64.rpm

Установка на стороне пользователя:

sudo dpkg -i dotplus_1.0.0_amd64.deb
# или
sudo rpm -i dotplus-1.0.0-1.x86_64.rpm

🔧 Как это устроено?

Проект включает шаблоны:

templates/control.in — шаблон для .deb

Package: dotplus
Version: {{VERSION}}
Section: utils
Priority: optional
Architecture: {{ARCH}}
Maintainer: Danil Nigmatullin <danil.communication@gmail.com>
Depends: {{DEPENDS}}
Description: QR and barcode generator with logo and CSV support (Rust CLI/GUI)
 DotPlus is a Rust-based GUI and command-line tool for generating QR codes and barcodes.
 It supports logo embedding, CSV import, and auto-update functionality.
 Suitable for both terminal workflows and desktop users.

templates/spec.in — шаблон для .rpm

Name:           dotplus
Version:        {{VERSION}}
Release:        1%{?dist}
Summary:        QR and barcode generator with logo and CSV support (Rust CLI/GUI)

License:        Freeware (Proprietary)
URL:            https://github.com/nigdanil/dotplus

Source0:        dotplus
BuildArch:      {{ARCH}}
Requires:       {{REQUIRES}}

%description
DotPlus is a Rust-based GUI and CLI tool for QR/barcode generation with logo and CSV support.

%prep
# No preparation steps needed

%install
[ -f %{SOURCE0} ] || { echo "Missing binary dotplus in SOURCES"; exit 1; }
[ -f %{_sourcedir}/arialmt.ttf ] || { echo "Missing font file arialmt.ttf"; exit 1; }

mkdir -p %{buildroot}/usr/bin
mkdir -p %{buildroot}/usr/share/dotplus/fonts

install -m 0755 %{SOURCE0} %{buildroot}/usr/bin/dotplus
install -m 0644 %{_sourcedir}/arialmt.ttf %{buildroot}/usr/share/dotplus/fonts/arialmt.ttf

%files
/usr/bin/dotplus
/usr/share/dotplus/fonts/arialmt.ttf

%changelog
* Mon Jun 30 2025 Danil Nigmatullin <danil.communication@gmail.com> - {{VERSION}}-1
- Initial RPM build

А также вспомогательный скрипт 📄 tools/generate.sh:

    # tools/generate.sh
    #!/usr/bin/env bash
    set -e

    VERSION="1.0.0"
    echo "🚀 Starting multi-arch build: version $VERSION"
    START=$(date +%s)

    ARCHS=(
      "amd64"    # x86_64-unknown-linux-gnu
      "arm64"    # aarch64-unknown-linux-gnu
      "armhf"    # armv7-unknown-linux-gnueabihf
    )
    TARGETS=(
      "x86_64-unknown-linux-gnu"
      "aarch64-unknown-linux-gnu"
      "armv7-unknown-linux-gnueabihf"
    )
    DEB_ARCHS=(
      "amd64"
      "arm64"
      "armhf"
    )
    RPM_ARCHS=(
      "x86_64"
      "aarch64"
      "armv7hl"
    )

    ROOT_DIR="$(git rev-parse --show-toplevel)"

    TEMPLATE_DIR="$ROOT_DIR/templates"

    mkdir -p build

    FAILED=()

    for i in "${!ARCHS[@]}"; do
      ARCH="${ARCHS[$i]}"
      TARGET="${TARGETS[$i]}"
      DEB_ARCH="${DEB_ARCHS[$i]}"
      RPM_ARCH="${RPM_ARCHS[$i]}"

      echo "🔧 Building for $ARCH ($TARGET)..."

      CROSS_SKIP_VERSION_CHECK=1 cross build \
        --release \
        --target "$TARGET" \
        --manifest-path Cargo.toml \
        --verbose || { echo "⚠️ Build failed for $TARGET"; FAILED+=("$ARCH"); continue; }

      BIN="target/$TARGET/release/dotplus"

      ls -lh "target/$TARGET/release"

      if [[ ! -f "$BIN" ]]; then
        echo "❌ Build failed for $TARGET"
        FAILED+=("$ARCH")
        continue
      fi

      BUILD_DIR="build/$ARCH"
      DEB_DIR="$BUILD_DIR/deb"
      RPM_DIR="$BUILD_DIR/rpm"

      mkdir -p "$DEB_DIR/DEBIAN"
      mkdir -p "$DEB_DIR/usr/bin"
      mkdir -p "$RPM_DIR/SOURCES"

      cp "$BIN" "$DEB_DIR/usr/bin/dotplus"
      cp "$BIN" "$RPM_DIR/SOURCES/dotplus"
      cp src/tools/font/arialmt.ttf "$RPM_DIR/SOURCES/arialmt.ttf"

      # Копируем ресурсные файлы (шрифты)
      mkdir -p "$DEB_DIR/usr/share/dotplus/fonts"
      cp src/tools/font/arialmt.ttf "$DEB_DIR/usr/share/dotplus/fonts/"

      # === .deb ===
      sed \
        -e "s/{{VERSION}}/$VERSION/" \
        -e "s/{{ARCH}}/$DEB_ARCH/" \
        -e "s/{{DEPENDS}}/libc6 (>= 2.29)/" \
        "$TEMPLATE_DIR/control.in" > "$DEB_DIR/DEBIAN/control"

      dpkg-deb --build "$DEB_DIR" "$BUILD_DIR/dotplus_${VERSION}_${DEB_ARCH}.deb"

      # === .rpm ===
      SPEC_OUT="$RPM_DIR/dotplus.spec"
      sed \
        -e "s/{{VERSION}}/$VERSION/" \
        -e "s/{{ARCH}}/$RPM_ARCH/" \
        -e "s/{{REQUIRES}}/glibc >= 2.29/" \
        "$TEMPLATE_DIR/spec.in" > "$SPEC_OUT"

      RPM_BUILDROOT="$RPM_DIR/BUILDROOT/dotplus-${VERSION}-1.${RPM_ARCH}"

      mkdir -p "$RPM_BUILDROOT/usr/bin"
      cp "$BIN" "$RPM_BUILDROOT/usr/bin/dotplus"
      chmod +x "$RPM_BUILDROOT/usr/bin/dotplus"

      # Копируем ресурсные файлы (шрифты)
      FONT_SOURCE="src/tools/font/arialmt.ttf"
      FONT_DEST="$RPM_DIR/BUILDROOT/dotplus-${VERSION}-1.${RPM_ARCH}/usr/share/dotplus/fonts"
      mkdir -p "$FONT_DEST"

      if [[ -f "$FONT_SOURCE" ]]; then
        cp "$FONT_SOURCE" "$FONT_DEST"
        echo "✅ Шрифт скопирован: $FONT_SOURCE → $FONT_DEST"
      else
        echo "⚠️ WARNING: $FONT_SOURCE не найден — удаляем строку из .spec"
        sed -i '/\/usr\/share\/dotplus\/fonts\/arialmt.ttf/d' "$SPEC_OUT"
      fi

      if [[ "$ARCH" == "amd64" ]]; then
        echo "📦 Building RPM for $ARCH..."
        rpmbuild \
          --define "_topdir $ROOT_DIR/$RPM_DIR" \
          --define "_sourcedir $ROOT_DIR/$RPM_DIR/SOURCES" \
          --define "_builddir $ROOT_DIR/$RPM_DIR/BUILD" \
          --define "_specdir $ROOT_DIR/$RPM_DIR" \
          --define "_rpmdir $ROOT_DIR/$RPM_DIR/RPMS" \
          --define "_buildrootdir $ROOT_DIR/$RPM_DIR/BUILDROOT" \
          --target "$RPM_ARCH-redhat-linux" \
          -bb "$SPEC_OUT" || {
            echo "❌ RPM build failed for $TARGET"
            FAILED+=("$ARCH")
            continue
          }

        RPM_OUTPUT=$(find "$RPM_DIR/RPMS" -name "*.rpm")
        if [[ -n "$RPM_OUTPUT" ]]; then
          echo "✅ RPM built for $ARCH: $RPM_OUTPUT"
        else
          echo "❌ RPM not found for $ARCH"
          FAILED+=("$ARCH")
        fi
      else
        echo "⚠️ Skipping RPM build for $ARCH"
      fi

      echo "✅ RPM build completed for $ARCH"
      
      echo "📁 RPM output dir listing:"
      ls -lR "$RPM_DIR"

      echo "📦 Checking built RPMs:"
      find "$RPM_DIR/RPMS" -type f 2>/dev/null || true

    done

    END=$(date +%s)
    DURATION=$((END - START))

    if [[ ${#FAILED[@]} -gt 0 ]]; then
      echo "❌ Failed builds: ${FAILED[*]}"
    else
      echo "✅ All target builds succeeded"
    fi

    echo "🎉 Build finished in $DURATION seconds."

    # 🧪 Покажем, какие пакеты были созданы
    echo "📦 Built package files:"
    find build -type f \( -name "*.deb" -o -name "*.rpm" \)

    # Подсчёт количества .deb и .rpm
    PACKAGE_COUNT=$(find build -type f \( -name "*.deb" -o -name "*.rpm" \) | wc -l | tr -d '[:space:]')
    
    echo "🧪 DEBUG: Found packages:"
    FOUND_PACKAGES=$(find build -type f \( -name "*.deb" -o -name "*.rpm" \))
    echo "$FOUND_PACKAGES"

    # Если ни одного пакета не создано — ошибка
    if [[ "$PACKAGE_COUNT" -lt 1 ]]; then
      echo "❌ No packages were created (check target paths or build errors)"
      echo "💡 Hint: verify that .deb and .rpm were written to expected build/**/ paths"
      exit 1
    fi

    echo "✅ Total packages created: $PACKAGE_COUNT"

Он принимает бинарник и архитектуру, генерирует .deb/.rpm с помощью dpkg-deb и rpmbuild, и сохраняет итоговые пакеты для релиза.

🐳 Docker-сборка

После сборки бинарников запускается Docker-сборка CLI-варианта DotPlus:

- name: Build Docker image
  run: |
    docker build -f docker/Dockerfile.cli -t ghcr.io/nigdanil/dotplus:latest .
    docker push ghcr.io/nigdanil/dotplus:latest

Простой Dockerfile.cli использует минимальную базу и добавляет только бинарник:

FROM debian:bookworm-slim
COPY dotplus /usr/local/bin/dotplus
ENTRYPOINT ["dotplus"]

Публикация артефактов

Все собранные файлы (бинарники, .deb, .rpm) автоматически прикрепляются к GitHub Release. Это упрощает дистрибуцию: пользователи могут выбрать нужную архитектуру и просто скачать готовый пакет.

🧩 Что пришлось учесть

  • musl и arm64-darwin не поддерживаются — нет стабильных образов или зависимости несовместимы

  • ⚠️ cross не кеширует образы между пушами, поэтому Docker нужен как для сборки, так и для доставки

📌 Итоговая картина релиза

Формат

Архитектуры

Описание

.tar.gz (бинарник)

x86_64, armhf, arm64

Универсальная ручная установка

.deb

x86_64, armhf, arm64

Ubuntu, Debian, Raspberry Pi

.rpm

x86_64

Fedora, RHEL, CentOS, openSUSE

Docker

Любая (универсально)

Без установки, CI/CD, DevOps

🐳 Docker: зачем он понадобился и как встроился в сборку

Изначально идея добавить Docker-образ DotPlus не стояла на первом месте. Основной упор делался на нативные бинарники и установочные пакеты. Однако в процессе развития проекта стало ясно: Docker — это не просто "в довесок", а необходимый инструмент, без которого:

  • невозможно обеспечить стабильную кросс-сборку в CI;

  • нельзя удобно использовать CLI в автоматических сценариях;

  • сложно дистрибутировать DotPlus в окружениях DevOps и серверов.

🔍 Зачем вообще нужен Docker?

Основные причины интеграции Docker:

  1. Надежная изоляция окружения в CI/CD
    Даже cross работает внутри Docker-контейнеров. Если ты не контролируешь окружение сборки (например, на GitHub Actions), Docker становится стандартом.

  2. Упрощённый запуск без установки
    CLI-версия DotPlus можно использовать прямо из Docker без установки бинарников, зависимостей и пакетов. Это особенно ценно для DevOps и автоматизации.

  3. Платформа-агностичный дистрибутив
    Один образ — один результат. Его поведение одинаково в любой системе, будь то Windows, Linux или macOS (с установленным Docker).

  4. Разделение GUI и CLI
    Docker используется только для CLI. Это упрощает образ, делает его минимальным и не тянет GUI-библиотеки.

🛠 Структура Dockerfile

В проекте используется Dockerfile.cli:

FROM debian:bookworm-slim
COPY dotplus /usr/local/bin/dotplus
ENTRYPOINT ["dotplus"]

Это минимальный образ (на базе slim-дистрибутива Debian), в который помещается только собранный бинарник dotplus. Никаких дополнительных зависимостей, библиотек или окружения не требуется.

⚙️ Интеграция в CI

Сборка Docker-образа происходит автоматически, после компиляции CLI:

- name: Build Docker image
  run: |
    docker build -f docker/Dockerfile.cli -t ghcr.io/nigdanil/dotplus:latest .
    docker push ghcr.io/nigdanil/dotplus:latest

Docker-образ публикуется в Docker Hub, откуда его может скачать любой пользователь:

docker pull nigdanil/dotplus-cli:latest

🚀 Как использовать Docker-версию DotPlus

Пример запуска CLI внутри Docker:

docker run --rm -v $(pwd):/out ghcr.io/nigdanil/dotplus:latest \
  --text "Docker test" --format qrcode --output /out/code.png

Объяснение:

  • --rm — удаляет контейнер после завершения

  • -v $(pwd):/out — монтирует текущую папку внутрь контейнера для вывода результата

  • --text, --format, --output — аргументы CLI DotPlus

Таким образом, можно использовать DotPlus в любом CI, на сервере, на macOS или даже в WSL — не устанавливая ничего, кроме Docker.

💻 Запуск DotPlus через Docker на Windows (.bat-файлы)

👉 Для пользователей Windows подготовлены удобные .bat-скрипты, которые вызывают CLI DotPlus внутри Docker-контейнера. Это позволяет запускать генерацию QR и штрихкодов без установки зависимостей.

📄 run-qr.bat — генерация QR-кодов

@echo off
REM Генерация QR-кодов из CSV через Docker

docker run --rm -v "%cd%\examples:/examples" nigdanil/dotplus-cli:1.0.0 ^
  --mode qr ^
  --csv "/examples/magnit/data/qr/magnit.csv" ^
  --logo "/examples/magnit/logo/v1.png" ^
  --output "/examples/magnit/img/qr" ^
  --cols 3 ^
  --rows 3 ^
  --qr-size 150 ^
  --font-size 24 ^
  --font-color "#000000"

pause

📄 run-barcode.bat — генерация EAN-13 штрихкодов

@echo off
REM Генерация штрихкодов EAN-13 из CSV через Docker

docker run --rm -v "%cd%\examples:/examples" nigdanil/dotplus-cli:1.0.0 ^
  --mode barcode ^
  --csv "/examples/magnit/data/barcode/magnit-barcodes-EAN-13.csv" ^
  --output "/examples/magnit/img/barcode" ^
  --barcode-type EAN-13 ^
  --cols 3 ^
  --rows 4 ^
  --width 300 ^
  --height 100 ^
  --font-size 22 ^
  --label-height 40 ^
  --offset-y 10 ^
  --spacing-x 20 ^
  --spacing-y 20

pause

📂 Структура проекта для скриптов

D:\dotplus-windows\
  ├── examples\
  ├── run-qr.bat
  └── run-barcode.bat

📌 Скрипты монтируют папку examples внутрь контейнера и сохраняют результат в удобное место. Всё, что нужно — это установленный Docker.

✅ Почему это удобно?

  • Не нужно устанавливать Rust, зависимости или сам dotplus

  • Работает на любой машине с Docker

  • Можно интегрировать в автоматизацию, скрипты, CI/CD

📌 Что удалось благодаря Docker

Проблема

Решение через Docker

Кросс-сборка в CI

cross + Docker-образы

Использование без установки

Образ с CLI доступен публично

Интеграция в shell-скрипты и пайплайны

CLI можно вызывать из любого скрипта

Минимизация зависимости

Образ содержит только dotplus бинарник

Вывод: Docker стал неотъемлемой частью инфраструктуры DotPlus. Он используется и в процессе сборки, и как самостоятельный способ запуска CLI. Это позволяет дистрибутировать инструмент в любую среду — будь то сервер, CI/CD или чужой компьютер без установки зависимостей.

📜 Лицензия DotPlus: от исходников к закрытому дистрибутиву

В первой версии DotPlus проект поставлялся с открытым кодом. Однако с релизом стабильных версий и запуском сборок под Linux, стало ясно: пора пересмотреть подход к лицензированию. Причин этому — несколько, и они связаны как с техническими, так и с юридическими и практическими аспектами.

В результате было принято решение:

📌 Перейти на бесплатную, но проприетарную лицензию.

❓ Почему так?

Вот ключевые причины:

  1. Минимизация рисков форков и переиспользования бренда
    Когда проект становится узнаваемым, велик риск "серых" клонов, которые могут нарушать философию продукта или использовать имя DotPlus без разрешения.

  2. Снижение нагрузки на поддержку
    Когда код открыт, пользователи часто создают собственные сборки, вносят изменения и потом задают вопросы, не относящиеся к официальной версии.

  3. Защита бизнес-модели и эксклюзивных алгоритмов
    DotPlus использует внутренние техники вставки логотипов, оптимизации QR, компактного вывода и т. д. Их защита — ключ к качеству конечного продукта.

  4. Фокус на стабильных бинарниках, а не на доработках со стороны сообщества
    Вся сборка и дистрибуция централизованы — это позволяет гарантировать качество и одинаковое поведение на всех системах.

✅ Что разрешено по новой лицензии?

  • 🔓 Бесплатное использование для любых целей — как в личных, так и в коммерческих проектах

  • 📦 Распространение неизменённых бинарников

  • 👥 Использование в организациях, автоматизации, CI/CD и т. п.

❌ Что запрещено?

  • 🚫 Изучение, анализ, декомпиляция и модификация бинарников

  • 🚫 Распространение модифицированных версий

  • 🚫 Попытки восстановить или раскрыть исходный код

📁 Как распространяется DotPlus сейчас?

  • ✅ Только в виде бинарников (.exe, .deb, .rpm, .tar.gz)

  • ✅ Через официальный GitHub Releases и Docker Registry

📄 Лицензионное соглашение (фрагмент)

Тип лицензии: Бесплатное ПО (проприетарное)
Исходный код: не распространяется
Использование: разрешено для личного и коммерческого применения
Обратная разработка: строго запрещена
Распространение: допустимо только в виде неизменённых бинарников с включением лицензионного соглашения
Авторские права: исходный код и все права на него остаются за автором

⚠️ Почему это всё равно честно?

Несмотря на закрытую лицензию, DotPlus остаётся:

  • полностью бесплатным;

  • стабильным и регулярно обновляемым;

  • совместимым с Linux, Windows, Docker;

  • понятным и удобным инструментом, который не требует онлайн-доступа или регистрации.

Более того, пользователь всё ещё получает CLI-инструмент, GUI-приложение и все опции (включая CSV, логотипы, экспорт) без ограничений функциональности.

Вывод: лицензия DotPlus теперь закрытая, но прозрачная. Программа остаётся бесплатной, распространяется в виде готовых бинарников и полностью пригодна для реального применения — без страха перед юридическими подводными камнями.

📈 Итоги и планы развития DotPlus

DotPlus прошёл большой путь от простой Windows-программы до полноценного кроссплатформенного инструмента с поддержкой CLI, GUI, Docker и релизами под Linux. Этот этап развития был посвящён тому, чтобы сделать проект устойчивым, универсальным и легко доставляемым в любой среде.

✅ Что реализовано

Возможность

Статус

Комментарий

🖥 GUI для Windows и Linux

✅ Готово

На базе eframe/egui, работает офлайн

🧾 CLI-интерфейс

✅ Готово

Генерация QR/штрихкодов через параметры

📦 DEB и RPM-пакеты

✅ В релизах

Для всех популярных дистрибутивов

🐳 Docker-образ

✅ Опубликован

Поддержка запуска без установки

🔄 CI/CD-сборка и релизы

✅ Автоматизировано

Публикация в GitHub Releases + GHCR

🔐 Проприетарная лицензия

✅ Введена

Бесплатно, без исходников, с разрешением на использование

🛠 Технические особенности

  • Используется cross для мультиархитектурной сборки (x86_64, ARMv7, AArch64)

  • Автоматическая генерация .deb и .rpm через скрипт tools/generate.sh

  • CI/CD на GitHub Actions, один YAML управляет всем пайплайном

  • Распространение Docker-образа через Docker Hub:

docker pull nigdanil/dotplus-cli:latest

🔮 Что в планах?

Вот направления, над которыми планируется работать в следующих релизах:

План

Статус

Комментарий

📄 Экспорт в PDF и SVG

🔜 В процессе

Для векторной печати и типографий

🌐 Web-версия на WASM

🔜 Исследуется

Возможность запуска в браузере без сервера

📄 Поддержка больших CSV

🔜 Планируется

Пакетная генерация с логами и ошибками

🔄 Автообновление для GUI

🔜 Будет

Особенно для Windows-версии

⚙️ Расширение CLI

🔜 Постепенно

Больше форматов, управление шаблонами

🔔 Интеграция уведомлений

🔜 Через notify-rust

Пока опциональная фича

🤝 Обратная связь и участие

Если вам не хватает какой-то функции, формат не поддерживается, или вы хотите предложить идею — открывайте issue на GitHub:

📌 https://github.com/nigdanil/dotplus

✅ Финальный вывод

DotPlus стал стабильным, мощным и универсальным инструментом для генерации QR и штрихкодов.
Поддержка разных архитектур, нативные пакеты, Docker и офлайн-режим делают его отличным выбором для всех — от домашних пользователей до CI-инфраструктур.

Программа продолжит развиваться. Спасибо всем, кто использует, тестирует и даёт обратную связь.

Tags:
Hubs:
+4
Comments4

Articles