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
59 changes: 59 additions & 0 deletions .github/workflows/container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Build & Push Container to GHCR

on:
push:
branches: []
tags: ["v*.*.*"]
pull_request:
branches: ["main"]
release:
types: [published]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}

- name: Build and push Docker image
uses: docker/build-push-action@v7
with:
context: .
file: ./container/Containerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
76 changes: 76 additions & 0 deletions container/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# ---------- Global definitions -----------
ARG envPath="/opt/inkcut-env"
ARG INKCUT_REPO="https://github.com/inkcut/inkcut.git"

# ---------- Stage 1: Builder ----------
FROM alpine:3 AS builder
ARG envPath
ARG INKCUT_REPO

# Install runtime + build dependencies
RUN apk add --no-cache \
python3 \
py3-lxml \
py3-pip \
py3-pycups \
py3-packaging \
py3-qt6 \
qt6-qtbase-dev \
qt6-qtwayland-dev \
build-base \
cups-dev \
git

# Create & activate python virtual environment (where inkcut will be installed)
RUN python3 -m venv --system-site-packages $envPath
ENV PATH="$envPath/bin:$PATH"

# Clone the github repository & build/install there-from
WORKDIR /src
RUN INKCUT_REF=$(git ls-remote --tags --sort="v:refname" $INKCUT_REPO | tail -n1 | sed 's/.*\///; s/\^{}//') && \
git clone --depth 1 --branch ${INKCUT_REF} ${INKCUT_REPO} inkcut-source
RUN pip install --no-cache-dir ./inkcut-source

# Generate the .desktop file
RUN mkdir -p $envPath/share/applications
RUN cat > $envPath/share/applications/inkcut.desktop <<EOL
[Desktop Entry]
Name=Inkcut
GenericName=Terminal entering Inkcut
Comment=Terminal entering Inkcut
Categories=Distrobox;System;Utility
Exec=inkcut
Icon=$envPath/share/icons/inkcut.svg
Keywords=distrobox;
NoDisplay=false
Terminal=false
Type=Application
EOL

RUN mkdir -p $envPath/share/icons
RUN cp $envPath/lib/python*/site-packages/inkcut/res/media/inkcut.svg $envPath/share/icons/inkcut.svg || true

# ---------- Stage 2: Runtime ----------
FROM alpine:3
ARG envPath

# Install runtime dependencies
RUN apk add --no-cache \
python3 \
py3-lxml \
py3-pycups \
py3-packaging \
py3-qt6 \
cups-libs \
qt6-qtbase \
qt6-qtsvg \
qt6-qtdeclarative \
qt6-qtserialport \
qt6-qtwayland

# Copy (& reference) the virtual environment from the builder stage
COPY --from=builder $envPath $envPath
ENV PATH="$envPath/bin:$PATH"

# Set the entrypoint
CMD ["inkcut"]
78 changes: 78 additions & 0 deletions container/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Inkcut via container image;
Install inkcut to your linux OS by running the `distrobox-assemble create` command below.
The python environment is already built-out, inkcut is ready-to-run.

This approach is distribution agnostic, and is ideal for use on immutable OS's.

## distrobox-assemble create
The paths and flags and apps-to-export are declared in a `distrobox.ini` file;
simply point the distrobox-assemble command to this file.

```sh
distrobox-assemble create \
--name inkcutEnv \
--file https://raw.githubusercontent.com/inkcut/inkcut/refs/heads/master/container/distrobox.ini
```

[distrobox.ini contents:](distrobox.ini)
```ini
[inkcutEnv]
name=inkcutEnv
image=ghcr.io/inkcut/inkcut:latest
home=$HOME/.local/share/distrobox/inkcutEnv
additional_flags="--group-add keep-groups"
exported_apps=/opt/inkcut-env/share/applications/inkcut.desktop
exported_bins=/opt/inkcut-env/bin/inkcut
exported_bins_path="$HOME/.local/bin"
pull=true
replace=true
```

# Error: 'Permission denied: /dev/tty...'
When using serial interfaces, this is a common (& expected) error.
There are special permissions required to allow inkcut to access the hardware.

## Safe-enough, easiest:
Add 'yourusername' to the `dialout` group.

This provides the user with access to more devices than is really needed, but is not likely a problem if you are the primary & sole user of the system.
```sh
sudo usermod -aG dialout yourusername
#logout & back in for group permissions to take effect
```

## More targeted approach:
Device access via udev rule

### Create udev rule for one specific device, and limit access to one user.
common path & filename: `/etc/udev/rules.d/50-usb-serial.rules`

example contents:
This means using the vendor ID and product ID in the UDEV rule.
```yml
# Match specific USB serial device by vendor and product ID
SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", GROUP="yourusername", MODE="0660"
```

### Grant privilege to a range of devices, but limit access to one user
```yml
KERNEL=="ttyACM[0-9]*", SUBSYSTEMS=="usb", GROUP="yourusername", MODE:="0660", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# or for some usb-serial interfaces:
KERNEL=="ttyUSB[0-9]*", SUBSYSTEMS=="usb", GROUP="yourusername", MODE:="0660", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
```

### Once you have chosen your udev approach:
```sh
[cyril@bluefin ~]$ sudo udevadm control --reload-rules
[cyril@bluefin ~]$ sudo udevadm trigger
```

after running one of the above udev rules, we can see that we have permissions from inside the container:
```sh
[cyril@bluefin ~]$ ls -l /dev/ttyA*
crw-rw---- 1 root cyril 166, 0 Jun 26 08:09 /dev/ttyACM0
[cyril@bluefin ~]$ distrobox enter inkcutEnv
📦[cyril@inkcutEnv cyril]$ ls -l /dev/ttyA*
crw-rw---- 1 nobody cyril 166, 0 Jun 26 08:09 /dev/ttyACM0
📦[cyril@inkcutEnv cyril]$
```
10 changes: 10 additions & 0 deletions container/distrobox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[inkcutEnv]
name=inkcutEnv
image=ghcr.io/inkcut/inkcut:latest
home=$HOME/.local/share/distrobox/inkcutEnv
additional_flags="--group-add keep-groups"
exported_apps=/opt/inkcut-env/share/applications/inkcut.desktop
exported_bins=/opt/inkcut-env/bin/inkcut
exported_bins_path="$HOME/.local/bin"
pull=true
replace=true