From b14b0946e2c501114dbd5e89de26ae2e5e1d34da Mon Sep 17 00:00:00 2001 From: purian23 Date: Sun, 22 Feb 2026 15:44:42 -0500 Subject: [PATCH] feat: DMS Greeter packaging for Debian/OpenSUSE on OBS --- .github/workflows/run-obs.yml | 245 ++++++++----- distro/debian/dms-greeter/_service | 9 + distro/debian/dms-greeter/debian/changelog | 6 + distro/debian/dms-greeter/debian/control | 23 ++ distro/debian/dms-greeter/debian/copyright | 27 ++ distro/debian/dms-greeter/debian/postinst | 108 ++++++ distro/debian/dms-greeter/debian/postrm | 14 + distro/debian/dms-greeter/debian/rules | 48 +++ .../debian/dms-greeter/debian/source/format | 1 + .../debian/dms-greeter/debian/source/options | 1 + distro/opensuse/dms-greeter.spec | 322 ++++++++++++++++++ distro/scripts/obs-status.sh | 11 +- distro/scripts/obs-upload.sh | 162 ++++++++- quickshell/Modules/Greetd/README.md | 64 ++-- quickshell/Modules/Greetd/assets/dms-greeter | 33 +- 15 files changed, 951 insertions(+), 123 deletions(-) create mode 100644 distro/debian/dms-greeter/_service create mode 100644 distro/debian/dms-greeter/debian/changelog create mode 100644 distro/debian/dms-greeter/debian/control create mode 100644 distro/debian/dms-greeter/debian/copyright create mode 100644 distro/debian/dms-greeter/debian/postinst create mode 100644 distro/debian/dms-greeter/debian/postrm create mode 100644 distro/debian/dms-greeter/debian/rules create mode 100644 distro/debian/dms-greeter/debian/source/format create mode 100644 distro/debian/dms-greeter/debian/source/options create mode 100644 distro/opensuse/dms-greeter.spec diff --git a/.github/workflows/run-obs.yml b/.github/workflows/run-obs.yml index e471fef6..1b96d544 100644 --- a/.github/workflows/run-obs.yml +++ b/.github/workflows/run-obs.yml @@ -10,6 +10,7 @@ on: options: - dms - dms-git + - dms-greeter - all default: "dms" rebuild_release: @@ -72,12 +73,27 @@ jobs: fi } + # Helper function to check dms-greeter stable tag + check_dms_greeter_stable() { + LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "") + local OBS_SPEC=$(curl -s -u "$OBS_USERNAME:$OBS_PASSWORD" "https://api.opensuse.org/source/home:AvengeMedia:danklinux/dms-greeter/dms-greeter.spec" 2>/dev/null || echo "") + local OBS_VERSION=$(echo "$OBS_SPEC" | grep "^Version:" | awk '{print $2}' | xargs | sed 's/^v//') + + if [[ -n "$LATEST_TAG" && "$LATEST_TAG" == "v$OBS_VERSION" ]]; then + echo "πŸ“‹ dms-greeter: Tag $LATEST_TAG already exists, skipping" + return 1 # No update needed + else + echo "πŸ“‹ dms-greeter: New tag ${LATEST_TAG:-unknown} (OBS has ${OBS_VERSION:-none})" + return 0 # Update needed + fi + } + # Main logic REBUILD="${{ github.event.inputs.rebuild_release }}" - if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then - # Tag selected or pushed - always update stable package - echo "packages=dms" >> $GITHUB_OUTPUT + if [[ "${{ github.ref }}" =~ ^refs/tags/ ]] && [[ -z "${{ github.event.inputs.package }}" ]]; then + # Run from tag with no package specified - update both stable packages + echo "packages=dms dms-greeter" >> $GITHUB_OUTPUT VERSION="${GITHUB_REF#refs/tags/}" echo "version=$VERSION" >> $GITHUB_OUTPUT echo "has_updates=true" >> $GITHUB_OUTPUT @@ -112,6 +128,10 @@ jobs: echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT fi fi + if check_dms_greeter_stable; then + PACKAGES_TO_UPDATE+=("dms-greeter") + [[ -n "$LATEST_TAG" ]] && echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT + fi if [[ ${#PACKAGES_TO_UPDATE[@]} -gt 0 ]]; then echo "packages=${PACKAGES_TO_UPDATE[*]}" >> $GITHUB_OUTPUT @@ -144,6 +164,18 @@ jobs: echo "has_updates=false" >> $GITHUB_OUTPUT fi + elif [[ "$PKG" == "dms-greeter" ]]; then + if check_dms_greeter_stable; then + echo "packages=$PKG" >> $GITHUB_OUTPUT + echo "has_updates=true" >> $GITHUB_OUTPUT + if [[ -n "$LATEST_TAG" ]]; then + echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT + fi + else + echo "packages=" >> $GITHUB_OUTPUT + echo "has_updates=false" >> $GITHUB_OUTPUT + fi + else # Unknown package - proceed anyway echo "packages=$PKG" >> $GITHUB_OUTPUT @@ -171,15 +203,8 @@ jobs: - name: Determine packages to update id: packages run: | - # Check if GITHUB_REF points to a tag (works for both push events and workflow_dispatch with tag selected) - if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then - # Tag selected or pushed - use the tag from GITHUB_REF - echo "packages=dms" >> $GITHUB_OUTPUT - VERSION="${GITHUB_REF#refs/tags/}" - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Using tag from GITHUB_REF: $VERSION" - # Check if check-updates already determined a version (from auto-detection) - elif [[ -n "${{ needs.check-updates.outputs.version }}" ]]; then + # Use check-updates outputs when available + if [[ -n "${{ needs.check-updates.outputs.version }}" ]]; then # Use version from check-updates job echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT echo "version=${{ needs.check-updates.outputs.version }}" >> $GITHUB_OUTPUT @@ -191,40 +216,16 @@ jobs: elif [[ -n "${{ github.event.inputs.package }}" ]]; then # Manual workflow dispatch - # Determine version for dms stable - if [[ "${{ github.event.inputs.package }}" == "dms" ]]; then - # Use github.ref if tag selected, otherwise auto-detect latest - if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then - VERSION="${GITHUB_REF#refs/tags/}" - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Using tag from GITHUB_REF: $VERSION" + # Determine version for dms stable and dms-greeter using the API + # GITHUB_REF is unreliable when "Use workflow from" a tag; API works from any ref + if [[ "${{ github.event.inputs.package }}" == "dms" ]] || [[ "${{ github.event.inputs.package }}" == "dms-greeter" ]] || [[ "${{ github.event.inputs.package }}" == "all" ]]; then + LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "") + if [[ -n "$LATEST_TAG" ]]; then + echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT + echo "Using latest release from API: $LATEST_TAG" else - # Auto-detect latest release for dms - LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "") - if [[ -n "$LATEST_TAG" ]]; then - echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT - echo "Auto-detected latest release: $LATEST_TAG" - else - echo "ERROR: Could not auto-detect latest release" - exit 1 - fi - fi - elif [[ "${{ github.event.inputs.package }}" == "all" ]]; then - # Use github.ref if tag selected, otherwise auto-detect latest - if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then - VERSION="${GITHUB_REF#refs/tags/}" - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Using tag from GITHUB_REF: $VERSION" - else - # Auto-detect latest release for "all" - LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "") - if [[ -n "$LATEST_TAG" ]]; then - echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT - echo "Auto-detected latest release: $LATEST_TAG" - else - echo "ERROR: Could not auto-detect latest release" - exit 1 - fi + echo "ERROR: Could not fetch latest release from API" + exit 1 fi fi @@ -283,55 +284,66 @@ jobs: echo " -- Avenge Media $CHANGELOG_DATE" } > "distro/debian/dms-git/debian/changelog" - - name: Update dms stable version + - name: Update stable version (dms + dms-greeter) if: steps.packages.outputs.version != '' run: | VERSION="${{ steps.packages.outputs.version }}" VERSION_NO_V="${VERSION#v}" + PACKAGES="${{ steps.packages.outputs.packages }}" echo "==> Updating packaging files to version: $VERSION_NO_V" - # Update spec file - sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec + # Update dms spec and changelog when dms is in the upload list + if [[ "$PACKAGES" == *"dms"* ]]; then + sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec + UPDATED_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1) + echo "βœ“ dms spec now shows Version: $UPDATED_VERSION" - # Verify the update - UPDATED_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1) - echo "βœ“ Spec file now shows Version: $UPDATED_VERSION" + DATE_STR=$(date "+%a %b %d %Y") + LOCAL_SPEC_HEAD=$(sed -n '1,/%changelog/{ /%changelog/d; p }' distro/opensuse/dms.spec) + { + echo "$LOCAL_SPEC_HEAD" + echo "%changelog" + echo "* $DATE_STR AvengeMedia - ${VERSION_NO_V}-1" + echo "- Update to stable $VERSION release" + } > distro/opensuse/dms.spec - # Single changelog entry (full history on OBS website) - DATE_STR=$(date "+%a %b %d %Y") - LOCAL_SPEC_HEAD=$(sed -n '1,/%changelog/{ /%changelog/d; p }' distro/opensuse/dms.spec) - { - echo "$LOCAL_SPEC_HEAD" - echo "%changelog" - echo "* $DATE_STR AvengeMedia - ${VERSION_NO_V}-1" - echo "- Update to stable $VERSION release" - } > distro/opensuse/dms.spec - - # Update Debian _service files (both tar_scm and download_url formats) - for service in distro/debian/*/_service; do - if [[ -f "$service" ]]; then - # Update tar_scm revision parameter (for dms-git) - sed -i "s|v[0-9.]*|$VERSION|" "$service" - - # Update download_url paths (for dms stable) - sed -i "s|/v[0-9.]\+/|/$VERSION/|g" "$service" - sed -i "s|/tags/v[0-9.]\+\.tar\.gz|/tags/$VERSION.tar.gz|g" "$service" + if [[ -f "distro/debian/dms/debian/changelog" ]]; then + CHANGELOG_DATE=$(date -R) + { + echo "dms (${VERSION_NO_V}db1) stable; urgency=medium" + echo "" + echo " * Update to $VERSION stable release" + echo "" + echo " -- Avenge Media $CHANGELOG_DATE" + } > "distro/debian/dms/debian/changelog" + echo "βœ“ Updated dms changelog to ${VERSION_NO_V}db1" fi - done + fi - # Update Debian changelog for dms stable (single entry, history on OBS website) - if [[ -f "distro/debian/dms/debian/changelog" ]]; then + # Update dms-greeter changelog when dms-greeter is in the upload list + if [[ "$PACKAGES" == *"dms-greeter"* ]] && [[ -f "distro/debian/dms-greeter/debian/changelog" ]]; then CHANGELOG_DATE=$(date -R) { - echo "dms (${VERSION_NO_V}db1) stable; urgency=medium" + echo "dms-greeter (${VERSION_NO_V}db1) unstable; urgency=medium" echo "" echo " * Update to $VERSION stable release" echo "" echo " -- Avenge Media $CHANGELOG_DATE" - } > "distro/debian/dms/debian/changelog" - echo "βœ“ Updated Debian changelog to ${VERSION_NO_V}db1" + } > "distro/debian/dms-greeter/debian/changelog" + echo "βœ“ Updated dms-greeter changelog to ${VERSION_NO_V}db1" fi + # Update Debian _service files for packages in upload list (download_url paths) + for service in distro/debian/*/_service; do + if [[ -f "$service" ]]; then + # Update tar_scm revision parameter (for dms-git) + sed -i "s|v[0-9.]*|$VERSION|" "$service" + # Update download_url paths (for dms, dms-greeter stable) + sed -i "s|/v[0-9.]\+/|/$VERSION/|g" "$service" + sed -i "s|/tags/v[0-9.]\+\.tar\.gz|/tags/$VERSION.tar.gz|g" "$service" + fi + done + - name: Install Go uses: actions/setup-go@v5 with: @@ -354,6 +366,7 @@ jobs: chmod 600 ~/.config/osc/oscrc - name: Upload to OBS + id: upload env: REBUILD_RELEASE: ${{ github.event.inputs.rebuild_release }} TAG_VERSION: ${{ steps.packages.outputs.version }} @@ -362,6 +375,8 @@ jobs: if [[ -z "$PACKAGES" ]]; then echo "βœ“ No packages need uploading. All up to date!" + echo "uploaded_packages=" >> $GITHUB_OUTPUT + echo "skipped_packages=" >> $GITHUB_OUTPUT exit 0 fi @@ -371,6 +386,9 @@ jobs: echo "==> Version being uploaded: ${{ steps.packages.outputs.version }}" fi + UPLOADED_PACKAGES=() + SKIPPED_PACKAGES=() + # PACKAGES can be space-separated list (e.g., "dms-git dms" from "all" check) # Loop through each package and upload for PKG in $PACKAGES; do @@ -382,13 +400,37 @@ jobs: fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + LOG_FILE=$(mktemp) + set +e if [[ "$PKG" == "dms-git" ]]; then - bash distro/scripts/obs-upload.sh dms-git "Automated git update" + bash distro/scripts/obs-upload.sh dms-git "Automated git update" >"$LOG_FILE" 2>&1 else - bash distro/scripts/obs-upload.sh "$PKG" "$MESSAGE" + bash distro/scripts/obs-upload.sh "$PKG" "$MESSAGE" >"$LOG_FILE" 2>&1 fi + STATUS=$? + set -e + + cat "$LOG_FILE" + + if [[ $STATUS -ne 0 ]]; then + rm -f "$LOG_FILE" + echo "❌ Upload failed for $PKG" + exit $STATUS + fi + + if grep -Eq "Exiting gracefully \(no changes needed\)|No changes needed for this package\. Exiting gracefully\." "$LOG_FILE"; then + echo "ℹ️ $PKG is already up to date. Skipped." + SKIPPED_PACKAGES+=("$PKG") + else + UPLOADED_PACKAGES+=("$PKG") + fi + + rm -f "$LOG_FILE" done + echo "uploaded_packages=${UPLOADED_PACKAGES[*]}" >> $GITHUB_OUTPUT + echo "skipped_packages=${SKIPPED_PACKAGES[*]}" >> $GITHUB_OUTPUT + - name: Summary if: always() run: | @@ -402,20 +444,59 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "All packages are current. Run completed successfully." >> $GITHUB_STEP_SUMMARY else - echo "**Packages Uploaded:**" >> $GITHUB_STEP_SUMMARY + UPLOADED_PACKAGES="${{ steps.upload.outputs.uploaded_packages }}" + SKIPPED_PACKAGES="${{ steps.upload.outputs.skipped_packages }}" + TOTAL_COUNT=$(wc -w <<<"$PACKAGES" | tr -d ' ') + UPLOADED_COUNT=0 + SKIPPED_COUNT=0 + if [[ -n "$UPLOADED_PACKAGES" ]]; then + UPLOADED_COUNT=$(wc -w <<<"$UPLOADED_PACKAGES" | tr -d ' ') + fi + if [[ -n "$SKIPPED_PACKAGES" ]]; then + SKIPPED_COUNT=$(wc -w <<<"$SKIPPED_PACKAGES" | tr -d ' ') + fi + in_list() { + local item="$1" + local list="$2" + [[ " $list " == *" $item "* ]] + } + + if [[ "${{ job.status }}" == "success" ]]; then + echo "**Status:** βœ… Completed successfully" >> $GITHUB_STEP_SUMMARY + else + echo "**Status:** ❌ Completed with errors" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Processed:** $TOTAL_COUNT package(s)" >> $GITHUB_STEP_SUMMARY + echo "**Uploaded:** $UPLOADED_COUNT package(s)" >> $GITHUB_STEP_SUMMARY + echo "**Skipped (up to date):** $SKIPPED_COUNT package(s)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Packages:**" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY for PKG in $PACKAGES; do + STATUS_ICON="βœ…" + STATUS_TEXT="uploaded" + if in_list "$PKG" "$SKIPPED_PACKAGES"; then + STATUS_ICON="ℹ️" + STATUS_TEXT="up to date (skipped)" + elif ! in_list "$PKG" "$UPLOADED_PACKAGES"; then + STATUS_ICON="❌" + STATUS_TEXT="failed" + fi + case "$PKG" in dms) - echo "- βœ… **dms** β†’ [View builds](https://build.opensuse.org/package/show/home:AvengeMedia:dms/dms)" >> $GITHUB_STEP_SUMMARY + echo "- $STATUS_ICON **dms** ($STATUS_TEXT) β†’ [View builds](https://build.opensuse.org/package/show/home:AvengeMedia:dms/dms)" >> $GITHUB_STEP_SUMMARY ;; dms-git) - echo "- βœ… **dms-git** β†’ [View builds](https://build.opensuse.org/package/show/home:AvengeMedia:dms-git/dms-git)" >> $GITHUB_STEP_SUMMARY + echo "- $STATUS_ICON **dms-git** ($STATUS_TEXT) β†’ [View builds](https://build.opensuse.org/package/show/home:AvengeMedia:dms-git/dms-git)" >> $GITHUB_STEP_SUMMARY + ;; + dms-greeter) + echo "- $STATUS_ICON **dms-greeter** ($STATUS_TEXT) β†’ [View builds](https://build.opensuse.org/package/show/home:AvengeMedia:danklinux/dms-greeter)" >> $GITHUB_STEP_SUMMARY ;; esac done - echo "" >> $GITHUB_STEP_SUMMARY if [[ -n "${{ github.event.inputs.rebuild_release }}" ]]; then diff --git a/distro/debian/dms-greeter/_service b/distro/debian/dms-greeter/_service new file mode 100644 index 00000000..d201d1d9 --- /dev/null +++ b/distro/debian/dms-greeter/_service @@ -0,0 +1,9 @@ + + + + https + github.com + /AvengeMedia/DankMaterialShell/releases/download/v1.4.2/dms-qml.tar.gz + dms-qml.tar.gz + + diff --git a/distro/debian/dms-greeter/debian/changelog b/distro/debian/dms-greeter/debian/changelog new file mode 100644 index 00000000..1cfa0a17 --- /dev/null +++ b/distro/debian/dms-greeter/debian/changelog @@ -0,0 +1,6 @@ +dms-greeter (1.4.2db8) unstable; urgency=medium + + * Initial Debian OBS package + * Port from Ubuntu/Fedora packaging + + -- Avenge Media Sat, 21 Feb 2026 00:00:00 +0000 diff --git a/distro/debian/dms-greeter/debian/control b/distro/debian/dms-greeter/debian/control new file mode 100644 index 00000000..faf57748 --- /dev/null +++ b/distro/debian/dms-greeter/debian/control @@ -0,0 +1,23 @@ +Source: dms-greeter +Section: x11 +Priority: optional +Maintainer: Avenge Media +Build-Depends: debhelper-compat (= 13) +Standards-Version: 4.6.2 +Homepage: https://github.com/AvengeMedia/DankMaterialShell +Vcs-Browser: https://github.com/AvengeMedia/DankMaterialShell +Vcs-Git: https://github.com/AvengeMedia/DankMaterialShell.git + +Package: dms-greeter +Architecture: any +Depends: ${misc:Depends}, + greetd, + quickshell-git | quickshell +Recommends: niri | hyprland | sway +Description: DankMaterialShell greeter for greetd + DankMaterialShell greeter for greetd login manager. A modern, Material Design 3 + inspired greeter interface built with Quickshell for Wayland compositors. + . + Supports multiple compositors including Niri, Hyprland, and Sway with automatic + compositor detection and configuration. Features session selection, user + authentication, and dynamic theming. diff --git a/distro/debian/dms-greeter/debian/copyright b/distro/debian/dms-greeter/debian/copyright new file mode 100644 index 00000000..364012c9 --- /dev/null +++ b/distro/debian/dms-greeter/debian/copyright @@ -0,0 +1,27 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: dms-greeter +Upstream-Contact: Avenge Media LLC +Source: https://github.com/AvengeMedia/DankMaterialShell + +Files: * +Copyright: 2026 Avenge Media LLC +License: MIT + +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/distro/debian/dms-greeter/debian/postinst b/distro/debian/dms-greeter/debian/postinst new file mode 100644 index 00000000..0e316caf --- /dev/null +++ b/distro/debian/dms-greeter/debian/postinst @@ -0,0 +1,108 @@ +#!/bin/sh +set -e + +case "$1" in + configure) + # Create greeter user/group if they don't exist + if ! getent group greeter >/dev/null; then + addgroup --system greeter + fi + + if ! getent passwd greeter >/dev/null; then + adduser --system --ingroup greeter --home /var/lib/greeter \ + --shell /bin/bash --gecos "System Greeter" greeter + fi + + if [ -d /var/cache/dms-greeter ]; then + chown -R greeter:greeter /var/cache/dms-greeter 2>/dev/null || true + fi + + if [ -d /var/lib/greeter ]; then + chown -R greeter:greeter /var/lib/greeter 2>/dev/null || true + fi + + # Check and set graphical.target as default + CURRENT_TARGET=$(systemctl get-default 2>/dev/null || echo "unknown") + if [ "$CURRENT_TARGET" != "graphical.target" ]; then + systemctl set-default graphical.target >/dev/null 2>&1 || true + TARGET_STATUS="Set to graphical.target (was: $CURRENT_TARGET) βœ“" + else + TARGET_STATUS="Already graphical.target βœ“" + fi + + GREETD_CONFIG="/etc/greetd/config.toml" + CONFIG_STATUS="Not modified (already configured)" + + # Check if niri or hyprland exists + COMPOSITOR="niri" + if ! command -v niri >/dev/null 2>&1; then + if command -v Hyprland >/dev/null 2>&1; then + COMPOSITOR="hyprland" + fi + fi + + # If config doesn't exist, create a default one + if [ ! -f "$GREETD_CONFIG" ]; then + mkdir -p /etc/greetd + cat > "$GREETD_CONFIG" << 'GREETD_EOF' +[terminal] +vt = 1 + +[default_session] +user = "greeter" +command = "/usr/bin/dms-greeter --command COMPOSITOR_PLACEHOLDER" +GREETD_EOF + sed -i "s|COMPOSITOR_PLACEHOLDER|$COMPOSITOR|" "$GREETD_CONFIG" + CONFIG_STATUS="Created new config with $COMPOSITOR βœ“" + elif ! grep -q "dms-greeter" "$GREETD_CONFIG"; then + # Backup existing config + BACKUP_FILE="${GREETD_CONFIG}.backup-$(date +%Y%m%d-%H%M%S)" + cp "$GREETD_CONFIG" "$BACKUP_FILE" 2>/dev/null || true + + # Update command in default_session section + sed -i "/^\[default_session\]/,/^\[/ s|^command =.*|command = \"/usr/bin/dms-greeter --command $COMPOSITOR\"|" "$GREETD_CONFIG" + sed -i '/^\[default_session\]/,/^\[/ s|^user =.*|user = "greeter"|' "$GREETD_CONFIG" + CONFIG_STATUS="Updated existing config (backed up) with $COMPOSITOR βœ“" + fi + + # Only show banner on initial install + if [ -z "$2" ]; then + cat << 'EOF' + +========================================================================= + DMS Greeter Installation Complete! +========================================================================= + +Status: +EOF + echo " βœ“ Greetd config: $CONFIG_STATUS" + echo " βœ“ Default target: $TARGET_STATUS" + cat << 'EOF' + βœ“ Greeter user: Created + βœ“ Greeter directories: /var/cache/dms-greeter, /var/lib/greeter + +Next steps: + +1. Enable the greeter: + dms greeter enable + (This will automatically disable conflicting display managers, + set graphical.target, and enable greetd) + +2. Sync your theme with the greeter (optional): + dms greeter sync + +3. Check your setup: + dms greeter status + +Ready to test? Run: sudo systemctl start greetd +Documentation: https://danklinux.com/docs/dankgreeter/ +========================================================================= + +EOF + fi + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/distro/debian/dms-greeter/debian/postrm b/distro/debian/dms-greeter/debian/postrm new file mode 100644 index 00000000..88addad3 --- /dev/null +++ b/distro/debian/dms-greeter/debian/postrm @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +case "$1" in + purge) + # Remove greeter cache directory on purge + rm -rf /var/cache/dms-greeter 2>/dev/null || true + + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/distro/debian/dms-greeter/debian/rules b/distro/debian/dms-greeter/debian/rules new file mode 100644 index 00000000..acdd4ff4 --- /dev/null +++ b/distro/debian/dms-greeter/debian/rules @@ -0,0 +1,48 @@ +#!/usr/bin/make -f + +export DH_VERBOSE = 1 + +DEB_VERSION := $(shell dpkg-parsechangelog -S Version) +UPSTREAM_VERSION := $(shell echo $(DEB_VERSION) | sed 's/-[^-]*$$//') + +%: + dh $@ + +override_dh_auto_build: + : nothing to build, we use prebuilt tarball content + +override_dh_auto_install: + # Same pattern as dms: upstream from combined tarball (native format) + # Build root is either . (we're inside dms-qml) or has dms-qml/ subdir + SOURCE_DIR=""; \ + if [ -d dms-qml ]; then SOURCE_DIR="dms-qml"; \ + elif [ -f Modules/Greetd/assets/dms-greeter ]; then SOURCE_DIR="."; \ + fi; \ + if [ -n "$$SOURCE_DIR" ]; then \ + mkdir -p debian/dms-greeter/usr/share/quickshell/dms-greeter && \ + ( cd $$SOURCE_DIR && tar cf - --exclude=debian . ) | \ + ( cd debian/dms-greeter/usr/share/quickshell/dms-greeter && tar xf - ) && \ + install -Dm755 $$SOURCE_DIR/Modules/Greetd/assets/dms-greeter \ + debian/dms-greeter/usr/bin/dms-greeter && \ + install -Dm644 $$SOURCE_DIR/Modules/Greetd/README.md \ + debian/dms-greeter/usr/share/doc/dms-greeter/README.md && \ + install -Dm644 $$SOURCE_DIR/LICENSE \ + debian/dms-greeter/usr/share/doc/dms-greeter/LICENSE && \ + install -Dpm0644 $$SOURCE_DIR/systemd/tmpfiles-dms-greeter.conf \ + debian/dms-greeter/usr/lib/tmpfiles.d/dms-greeter.conf; \ + else \ + echo "ERROR: No upstream source (dms-qml or Modules/Greetd/assets/dms-greeter)!" && \ + echo "Contents of current directory:" && ls -la && exit 1; \ + fi + + # Remove build and development files + rm -rf debian/dms-greeter/usr/share/quickshell/dms-greeter/core + rm -rf debian/dms-greeter/usr/share/quickshell/dms-greeter/distro + rm -rf debian/dms-greeter/usr/share/quickshell/dms-greeter/.git* + rm -f debian/dms-greeter/usr/share/quickshell/dms-greeter/.gitignore + rm -rf debian/dms-greeter/usr/share/quickshell/dms-greeter/.github + +override_dh_auto_clean: + rm -rf dms-qml + # When build root is dms-qml itself, we're inside it - nothing extra to remove + dh_auto_clean diff --git a/distro/debian/dms-greeter/debian/source/format b/distro/debian/dms-greeter/debian/source/format new file mode 100644 index 00000000..89ae9db8 --- /dev/null +++ b/distro/debian/dms-greeter/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/distro/debian/dms-greeter/debian/source/options b/distro/debian/dms-greeter/debian/source/options new file mode 100644 index 00000000..807343fc --- /dev/null +++ b/distro/debian/dms-greeter/debian/source/options @@ -0,0 +1 @@ +# OBS _service downloads dms-qml.tar.gz; no extra excludes needed diff --git a/distro/opensuse/dms-greeter.spec b/distro/opensuse/dms-greeter.spec new file mode 100644 index 00000000..cc6e7e75 --- /dev/null +++ b/distro/opensuse/dms-greeter.spec @@ -0,0 +1,322 @@ +# Spec for DMS Greeter - OpenSUSE/OBS + +%global debug_package %{nil} +%global version VERSION_PLACEHOLDER +%global pkg_summary DankMaterialShell greeter for greetd + +Name: dms-greeter +Version: %{version} +Release: RELEASE_PLACEHOLDER%{?dist} +Summary: %{pkg_summary} + +License: MIT +URL: https://github.com/AvengeMedia/DankMaterialShell + +Source0: dms-qml.tar.gz + +BuildRequires: gzip +BuildRequires: wget +BuildRequires: systemd-rpm-macros + +Requires: greetd +Requires: (quickshell-git or quickshell) +Requires(post): /usr/sbin/useradd +Requires(post): /usr/sbin/groupadd + +Recommends: policycoreutils-python-utils +Recommends: acl +Suggests: niri +Suggests: hyprland +Suggests: sway + +%description +DankMaterialShell greeter for greetd login manager. A modern, Material Design 3 +inspired greeter interface built with Quickshell for Wayland compositors. + +Supports multiple compositors including Niri, Hyprland, and Sway with automatic +compositor detection and configuration. Features session selection, user +authentication, and dynamic theming. + +%prep +%setup -q -c -n dms-qml + +%build + +%install +# Install greeter files to shared data location +install -dm755 %{buildroot}%{_datadir}/quickshell/dms-greeter +cp -r %{_builddir}/dms-qml/* %{buildroot}%{_datadir}/quickshell/dms-greeter/ + +install -Dm755 %{_builddir}/dms-qml/Modules/Greetd/assets/dms-greeter %{buildroot}%{_bindir}/dms-greeter + +install -Dm644 %{_builddir}/dms-qml/Modules/Greetd/README.md %{buildroot}%{_docdir}/dms-greeter/README.md + +install -Dpm0644 %{_builddir}/dms-qml/systemd/tmpfiles-dms-greeter.conf %{buildroot}%{_tmpfilesdir}/dms-greeter.conf + +install -Dm644 %{_builddir}/dms-qml/LICENSE %{buildroot}%{_docdir}/dms-greeter/LICENSE + +install -dm755 %{buildroot}%{_sharedstatedir}/greeter + +# Remove build and development files +rm -rf %{buildroot}%{_datadir}/quickshell/dms-greeter/.git* +rm -f %{buildroot}%{_datadir}/quickshell/dms-greeter/.gitignore +rm -rf %{buildroot}%{_datadir}/quickshell/dms-greeter/.github +rm -rf %{buildroot}%{_datadir}/quickshell/dms-greeter/distro + +%posttrans +if [ -d "%{_sysconfdir}/xdg/quickshell/dms-greeter" ]; then + rmdir "%{_sysconfdir}/xdg/quickshell/dms-greeter" 2>/dev/null || true + rmdir "%{_sysconfdir}/xdg/quickshell" 2>/dev/null || true + rmdir "%{_sysconfdir}/xdg" 2>/dev/null || true +fi + +%files +%dir %{_docdir}/dms-greeter +%license %{_docdir}/dms-greeter/LICENSE +%doc %{_docdir}/dms-greeter/README.md +%{_bindir}/dms-greeter +%dir %{_datadir}/quickshell +%{_datadir}/quickshell/dms-greeter/ +%{_tmpfilesdir}/%{name}.conf + +%pre +# Create greeter user/group if they don't exist +getent group greeter >/dev/null || groupadd -r greeter +getent passwd greeter >/dev/null || \ + useradd -r -g greeter -d %{_sharedstatedir}/greeter -s /bin/bash \ + -c "System Greeter" greeter +exit 0 + +%post +# SELinux contexts (no-op on OpenSUSE - semanage/restorecon not present) +if [ -x /usr/sbin/semanage ] && [ -x /usr/sbin/restorecon ]; then + semanage fcontext -a -t bin_t '%{_bindir}/dms-greeter' >/dev/null 2>&1 || true + restorecon %{_bindir}/dms-greeter >/dev/null 2>&1 || true + semanage fcontext -a -t user_home_dir_t '%{_sharedstatedir}/greeter(/.*)?' >/dev/null 2>&1 || true + restorecon -R %{_sharedstatedir}/greeter >/dev/null 2>&1 || true + semanage fcontext -a -t cache_home_t '%{_localstatedir}/cache/dms-greeter(/.*)?' >/dev/null 2>&1 || true + restorecon -R %{_localstatedir}/cache/dms-greeter >/dev/null 2>&1 || true + semanage fcontext -a -t usr_t '%{_datadir}/quickshell/dms-greeter(/.*)?' >/dev/null 2>&1 || true + restorecon -R %{_datadir}/quickshell/dms-greeter >/dev/null 2>&1 || true + restorecon %{_sysconfdir}/pam.d/greetd >/dev/null 2>&1 || true +fi + +# Resolve greeter runtime account/group for distro differences +GREETER_USER="greeter" +for candidate in greeter greetd _greeter; do + if getent passwd "$candidate" >/dev/null 2>&1; then + GREETER_USER="$candidate" + break + fi +done + +GREETER_GROUP="$GREETER_USER" +if ! getent group "$GREETER_GROUP" >/dev/null 2>&1; then + for candidate in greeter greetd _greeter; do + if getent group "$candidate" >/dev/null 2>&1; then + GREETER_GROUP="$candidate" + break + fi + done +fi + +# Ensure proper ownership of greeter directories +chown -R "$GREETER_USER:$GREETER_GROUP" %{_localstatedir}/cache/dms-greeter 2>/dev/null || true +chown -R "$GREETER_USER:$GREETER_GROUP" %{_sharedstatedir}/greeter 2>/dev/null || true + +# Verify PAM configuration +PAM_CONFIG="/etc/pam.d/greetd" +write_greetd_pam_config() { + # openSUSE and Debian families usually expose PAM stacks as common-* + if [ -f /etc/pam.d/common-auth ] && [ -f /etc/pam.d/common-account ] && [ -f /etc/pam.d/common-password ] && [ -f /etc/pam.d/common-session ]; then + cat > "$PAM_CONFIG" << 'PAM_EOF' +#%PAM-1.0 +auth include common-auth +account required pam_nologin.so +account include common-account +password include common-password +session required pam_loginuid.so +session optional pam_keyinit.so force revoke +session include common-session +PAM_EOF + return + fi + + # Fedora/RHEL style system-auth/postlogin stack + if [ -f /etc/pam.d/system-auth ]; then + if [ -f /etc/pam.d/postlogin ]; then + cat > "$PAM_CONFIG" << 'PAM_EOF' +#%PAM-1.0 +auth substack system-auth +auth include postlogin +account required pam_nologin.so +account include system-auth +password include system-auth +session required pam_loginuid.so +session optional pam_keyinit.so force revoke +session include system-auth +session include postlogin +PAM_EOF + else + cat > "$PAM_CONFIG" << 'PAM_EOF' +#%PAM-1.0 +auth include system-auth +account required pam_nologin.so +account include system-auth +password include system-auth +session required pam_loginuid.so +session optional pam_keyinit.so force revoke +session include system-auth +PAM_EOF + fi + return + fi + + # Last-resort conservative fallback + cat > "$PAM_CONFIG" << 'PAM_EOF' +#%PAM-1.0 +auth required pam_unix.so nullok +account required pam_unix.so +password required pam_unix.so nullok sha512 +session required pam_unix.so +PAM_EOF +} + +if [ ! -f "$PAM_CONFIG" ]; then + write_greetd_pam_config + chmod 644 "$PAM_CONFIG" + [ "$1" -eq 1 ] && echo "Created PAM configuration for greetd" +else + NEEDS_PAM_UPDATE=0 + if grep -q "common-auth" "$PAM_CONFIG"; then + if [ ! -f /etc/pam.d/common-auth ]; then + NEEDS_PAM_UPDATE=1 + fi + elif grep -q "system-auth" "$PAM_CONFIG"; then + if [ ! -f /etc/pam.d/system-auth ]; then + NEEDS_PAM_UPDATE=1 + fi + else + NEEDS_PAM_UPDATE=1 + fi + + if [ "$NEEDS_PAM_UPDATE" -eq 1 ]; then + cp "$PAM_CONFIG" "$PAM_CONFIG.backup-dms-greeter" + write_greetd_pam_config + chmod 644 "$PAM_CONFIG" + [ "$1" -eq 1 ] && echo "Updated PAM configuration (old config backed up to $PAM_CONFIG.backup-dms-greeter)" + fi +fi + +# Auto-configure greetd config +GREETD_CONFIG="/etc/greetd/config.toml" +CONFIG_STATUS="Not modified (already configured)" + +COMPOSITOR="" +for candidate in niri Hyprland sway; do + if command -v "$candidate" >/dev/null 2>&1; then + case "$candidate" in + Hyprland) + COMPOSITOR="hyprland" + ;; + *) + COMPOSITOR="$candidate" + ;; + esac + break + fi +done + +if [ ! -f "$GREETD_CONFIG" ]; then + mkdir -p /etc/greetd + if [ -n "$COMPOSITOR" ]; then + cat > "$GREETD_CONFIG" << 'GREETD_EOF' +[terminal] +vt = 1 + +[default_session] +user = "GREETER_USER_PLACEHOLDER" +command = "/usr/bin/dms-greeter --command COMPOSITOR_PLACEHOLDER" +GREETD_EOF + sed -i "s|GREETER_USER_PLACEHOLDER|$GREETER_USER|" "$GREETD_CONFIG" + sed -i "s|COMPOSITOR_PLACEHOLDER|$COMPOSITOR|" "$GREETD_CONFIG" + CONFIG_STATUS="Created new config with $COMPOSITOR βœ“" + else + cat > "$GREETD_CONFIG" << 'GREETD_EOF' +[terminal] +vt = 1 + +[default_session] +user = "GREETER_USER_PLACEHOLDER" +command = "agreety --cmd /bin/login" +GREETD_EOF + sed -i "s|GREETER_USER_PLACEHOLDER|$GREETER_USER|" "$GREETD_CONFIG" + CONFIG_STATUS="Created safe fallback config (no supported compositor detected)" + fi +elif ! grep -q "dms-greeter" "$GREETD_CONFIG"; then + if [ -n "$COMPOSITOR" ]; then + BACKUP_FILE="${GREETD_CONFIG}.backup-$(date +%%Y%%m%%d-%%H%%M%%S)" + cp "$GREETD_CONFIG" "$BACKUP_FILE" 2>/dev/null || true + sed -i "/^\[default_session\]/,/^\[/ s|^command =.*|command = \"/usr/bin/dms-greeter --command $COMPOSITOR\"|" "$GREETD_CONFIG" + sed -i "/^\[default_session\]/,/^\[/ s|^user =.*|user = \"$GREETER_USER\"|" "$GREETD_CONFIG" + CONFIG_STATUS="Updated existing config (backed up) with $COMPOSITOR βœ“" + else + CONFIG_STATUS="Skipped dms-greeter command update (no supported compositor detected)" + fi +fi + +# Set graphical.target as default +CURRENT_TARGET=$(systemctl get-default 2>/dev/null || echo "unknown") +if [ "$CURRENT_TARGET" != "graphical.target" ]; then + systemctl set-default graphical.target >/dev/null 2>&1 || true + TARGET_STATUS="Set to graphical.target (was: $CURRENT_TARGET) βœ“" +else + TARGET_STATUS="Already graphical.target βœ“" +fi + +if [ "$1" -eq 1 ]; then +cat << 'EOF' + +========================================================================= + DMS Greeter Installation Complete! +========================================================================= + +Status: +EOF +echo " βœ“ Greetd config: $CONFIG_STATUS" +echo " βœ“ Default target: $TARGET_STATUS" +cat << 'EOF' + βœ“ Greeter user: Created + βœ“ Greeter directories: /var/cache/dms-greeter, /var/lib/greeter + βœ“ SELinux contexts: Applied (if applicable) + +Next steps: + +1. Enable the greeter: + dms greeter enable + +2. Sync your theme with the greeter (optional): + dms greeter sync + +3. Check your setup: + dms greeter status + +Ready to test? Run: sudo systemctl start greetd +Documentation: https://danklinux.com/docs/dankgreeter/ +========================================================================= + +EOF +fi + +%postun +if [ "$1" -eq 0 ] && [ -x /usr/sbin/semanage ]; then + semanage fcontext -d '%{_bindir}/dms-greeter' 2>/dev/null || true + semanage fcontext -d '%{_sharedstatedir}/greeter(/.*)?' 2>/dev/null || true + semanage fcontext -d '%{_localstatedir}/cache/dms-greeter(/.*)?' 2>/dev/null || true + semanage fcontext -d '%{_datadir}/quickshell/dms-greeter(/.*)?' 2>/dev/null || true +fi + +%changelog +* CHANGELOG_DATE_PLACEHOLDER AvengeMedia - VERSION_PLACEHOLDER-RELEASE_PLACEHOLDER +- Stable release VERSION_PLACEHOLDER +- Initial OpenSUSE/OBS port from Fedora diff --git a/distro/scripts/obs-status.sh b/distro/scripts/obs-status.sh index 903590f1..8545ef25 100755 --- a/distro/scripts/obs-status.sh +++ b/distro/scripts/obs-status.sh @@ -11,7 +11,7 @@ OBS_BASE_PROJECT="home:AvengeMedia" OBS_BASE="$HOME/.cache/osc-checkouts" -ALL_PACKAGES=(dms dms-git) +ALL_PACKAGES=(dms dms-git dms-greeter) REPOS=("Debian_13" "openSUSE_Tumbleweed" "16.0") ARCHES=("x86_64" "aarch64") @@ -41,6 +41,9 @@ for pkg in "${PACKAGES[@]}"; do dms-git) PROJECT="$OBS_BASE_PROJECT:dms-git" ;; + dms-greeter) + PROJECT="$OBS_BASE_PROJECT:danklinux" + ;; *) echo "Error: Unknown package '$pkg'" continue @@ -74,11 +77,15 @@ for pkg in "${PACKAGES[@]}"; do COLOR="\033[0;32m" # Green SYMBOL="βœ…" ;; - failed) + failed|broken|broken*) COLOR="\033[0;31m" # Red SYMBOL="❌" FAILED_BUILDS+=("$repo $arch") ;; + blocked) + COLOR="\033[0;33m" # Yellow + SYMBOL="⏸️" + ;; unresolvable) COLOR="\033[0;33m" # Yellow SYMBOL="⚠️" diff --git a/distro/scripts/obs-upload.sh b/distro/scripts/obs-upload.sh index 006debe0..bfcbef9d 100755 --- a/distro/scripts/obs-upload.sh +++ b/distro/scripts/obs-upload.sh @@ -68,13 +68,14 @@ fi OBS_BASE_PROJECT="home:AvengeMedia" OBS_BASE="$HOME/.cache/osc-checkouts" -AVAILABLE_PACKAGES=(dms dms-git) +AVAILABLE_PACKAGES=(dms dms-git dms-greeter) if [[ -z "$PACKAGE" ]]; then echo "Available packages:" echo "" echo " 1. dms - Stable DMS" echo " 2. dms-git - Nightly DMS" + echo " 3. dms-greeter - DMS greeter for greetd" echo " a. all" echo "" read -r -p "Select package (1-${#AVAILABLE_PACKAGES[@]}, a): " selection @@ -141,7 +142,12 @@ check_obs_version_exists() { return 0 fi else - echo "⚠️ Could not fetch OBS spec (API may be unavailable), proceeding anyway" + # Empty/invalid response: expected on first upload (no spec on server yet), or actual API failure + if [[ -z "$OBS_SPEC" ]]; then + echo " No existing spec on OBS (first upload?) - proceeding" + else + echo "⚠️ Could not fetch OBS spec (API may be unavailable), proceeding anyway" + fi return 1 fi return 1 @@ -168,6 +174,22 @@ update_debian_dms_service() { sed -i "s|/releases/download/v[0-9][^\"]*/dms-distropkg-arm64\.gz|/releases/download/v${base_version}/dms-distropkg-arm64.gz|" "$service_path" } +update_debian_dms_greeter_service() { + local service_path="$1" + if [[ -z "$service_path" || ! -f "$service_path" ]]; then + return 0 + fi + if [[ -z "$CHANGELOG_VERSION" ]]; then + return 0 + fi + local base_version + base_version=$(echo "$CHANGELOG_VERSION" | sed -E 's/^([0-9]+(\.[0-9]+)*).*/\1/') + if [[ -z "$base_version" ]]; then + return 0 + fi + sed -i "s|/releases/download/v[0-9][^\"]*/dms-qml\.tar\.gz|/releases/download/v${base_version}/dms-qml.tar.gz|" "$service_path" +} + update_opensuse_git_spec() { local spec_path="$1" if [[ -z "$spec_path" || ! -f "$spec_path" ]]; then @@ -248,6 +270,9 @@ dms) dms-git) PROJECT="dms-git" ;; +dms-greeter) + PROJECT="danklinux" + ;; *) echo "Error: Unknown package '$PACKAGE'" exit 1 @@ -329,9 +354,11 @@ if [[ -d "distro/debian/$PACKAGE/debian" ]]; then echo " - Applied rebuild suffix: $CHANGELOG_VERSION" fi - # Keep Debian dms _service in sync with changelog version + # Keep Debian _service in sync with changelog version if [[ "$PACKAGE" == "dms" ]] && [[ -f "distro/debian/$PACKAGE/_service" ]]; then update_debian_dms_service "distro/debian/$PACKAGE/_service" + elif [[ "$PACKAGE" == "dms-greeter" ]] && [[ -f "distro/debian/$PACKAGE/_service" ]]; then + update_debian_dms_greeter_service "distro/debian/$PACKAGE/_service" fi # Check if this version already exists in OBS @@ -341,6 +368,12 @@ if [[ -d "distro/debian/$PACKAGE/debian" ]]; then if [[ "$PACKAGE" == *"-git" ]]; then echo "==> Error: This commit is already uploaded to OBS" echo " The same git commit ($(echo "$CHANGELOG_VERSION" | grep -oP '[a-f0-9]{8}' | tail -1)) already exists on OBS." + if [[ -n "${GITHUB_ACTIONS:-}" ]] || [[ -n "${CI:-}" ]]; then + echo " CI run detected: skipping upload as a no-op (already up to date)." + echo " If you need to force rebuild this same commit, set REBUILD_RELEASE (e.g. 2, 3, ...)." + echo "βœ“ Exiting gracefully (no changes needed)" + exit 0 + fi echo " To rebuild the same commit, specify a rebuild number:" echo " ./distro/scripts/obs-upload.sh $PACKAGE 2" echo " ./distro/scripts/obs-upload.sh $PACKAGE 3" @@ -379,6 +412,13 @@ if [[ "$UPLOAD_OPENSUSE" == true ]] && [[ -f "distro/opensuse/$PACKAGE.spec" ]]; if [[ "$PACKAGE" == *"-git" ]] && [[ -n "$CHANGELOG_VERSION" ]]; then update_opensuse_git_spec "$WORK_DIR/$PACKAGE.spec" + elif [[ "$PACKAGE" == "dms-greeter" ]] && [[ -n "$CHANGELOG_VERSION" ]]; then + DMS_GREETER_BASE_VERSION=$(echo "$CHANGELOG_VERSION" | sed -E 's/^([0-9]+(\.[0-9]+)*).*/\1/') + DMS_GREETER_RELEASE=$(echo "$CHANGELOG_VERSION" | sed -E 's/.*db([0-9]+)$/\1/' || echo "1") + CHANGELOG_DATE=$(date '+%a %b %d %Y') + sed -i "s/VERSION_PLACEHOLDER/${DMS_GREETER_BASE_VERSION}/g" "$WORK_DIR/$PACKAGE.spec" + sed -i "s/RELEASE_PLACEHOLDER/${DMS_GREETER_RELEASE}/g" "$WORK_DIR/$PACKAGE.spec" + sed -i "s/CHANGELOG_DATE_PLACEHOLDER/${CHANGELOG_DATE}/g" "$WORK_DIR/$PACKAGE.spec" fi if [[ -f "$WORK_DIR/.osc/$PACKAGE.spec" ]]; then @@ -444,6 +484,24 @@ if [[ "$UPLOAD_OPENSUSE" == true ]] && [[ "$UPLOAD_DEBIAN" == false ]] && [[ -f fi fi + # For dms-greeter: download dms-qml.tar.gz from _service URL + if [[ -z "${SOURCE_DIR:-}" ]] && [[ "$PACKAGE" == "dms-greeter" ]] && [[ -f "distro/debian/$PACKAGE/_service" ]]; then + DMS_GREETER_URL=$(grep -A 5 'name="download_url"' "distro/debian/$PACKAGE/_service" | grep "path" | sed 's/.*\(.*\)<\/param>.*/\1/' | head -1) + if [[ -n "$DMS_GREETER_URL" ]]; then + DMS_GREETER_FULL_URL="https://github.com${DMS_GREETER_URL}" + echo " Downloading dms-greeter source from: $DMS_GREETER_FULL_URL" + if wget -q -O "$TEMP_DIR/dms-qml.tar.gz" "$DMS_GREETER_FULL_URL" 2>/dev/null || \ + curl -L -f -s -o "$TEMP_DIR/dms-qml.tar.gz" "$DMS_GREETER_FULL_URL" 2>/dev/null; then + cd "$TEMP_DIR" + tar -xzf dms-qml.tar.gz + if [[ -f "Modules/Greetd/assets/dms-greeter" ]]; then + SOURCE_DIR="$TEMP_DIR" + fi + cd "$REPO_ROOT" + fi + fi + fi + if [[ -n "$SOURCE_DIR" && -d "$SOURCE_DIR" ]]; then SOURCE0=$(grep "^Source0:" "distro/opensuse/$PACKAGE.spec" | awk '{print $2}' | head -1) @@ -452,6 +510,15 @@ if [[ "$UPLOAD_OPENSUSE" == true ]] && [[ "$UPLOAD_DEBIAN" == false ]] && [[ -f cd "$OBS_TARBALL_DIR" case "$PACKAGE" in + dms-greeter) + EXPECTED_DIR="dms-qml" + echo " Creating $SOURCE0 (directory: $EXPECTED_DIR)" + mkdir -p "$EXPECTED_DIR" + cp -a "$SOURCE_DIR"/. "$EXPECTED_DIR/" + tar -czf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR" + rm -rf "$EXPECTED_DIR" + echo " Created $SOURCE0 ($(stat -c%s "$WORK_DIR/$SOURCE0" 2>/dev/null || echo 0) bytes)" + ;; dms) DMS_VERSION=$(grep "^Version:" "$REPO_ROOT/distro/opensuse/$PACKAGE.spec" | sed 's/^Version:[[:space:]]*//' | head -1) EXPECTED_DIR="DankMaterialShell-${DMS_VERSION}" @@ -584,6 +651,15 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t if [[ -z "$SOURCE_DIR" ]]; then SOURCE_DIR=$(find . -maxdepth 1 -type d ! -name "." | head -1) fi + # dms-qml.tar.gz extracts flat (quickshell contents, no top-level dir) + # Create dms-qml wrapper so combined tarball has correct top-level dir (like dms) + if [[ "$PACKAGE" == "dms-greeter" ]] && [[ -f "Modules/Greetd/assets/dms-greeter" ]]; then + mkdir -p dms-qml + for f in *; do + [[ -e "$f" && "$f" != "dms-qml" && "$f" != "source-archive" ]] && mv "$f" dms-qml/ 2>/dev/null || true + done + SOURCE_DIR="dms-qml" + fi if [[ -z "$SOURCE_DIR" || ! -d "$SOURCE_DIR" ]]; then echo "Error: Failed to extract source archive or find source directory" echo "Contents of $TEMP_DIR:" @@ -660,6 +736,21 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t cd "$OBS_TARBALL_DIR" case "$PACKAGE" in + dms-greeter) + EXPECTED_DIR="dms-qml" + echo " Creating $SOURCE0 (directory: $EXPECTED_DIR)" + mkdir -p "$EXPECTED_DIR" + cp -a "$SOURCE_DIR"/. "$EXPECTED_DIR/" + if [[ "$SOURCE0" == *.tar.xz ]]; then + tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -cJf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR" + elif [[ "$SOURCE0" == *.tar.bz2 ]]; then + tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -cjf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR" + else + tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR" + fi + rm -rf "$EXPECTED_DIR" + echo " Created $SOURCE0 ($(stat -c%s "$WORK_DIR/$SOURCE0" 2>/dev/null || echo 0) bytes)" + ;; dms) DMS_VERSION=$(grep "^Version:" "$REPO_ROOT/distro/opensuse/$PACKAGE.spec" | sed 's/^Version:[[:space:]]*//' | head -1) EXPECTED_DIR="DankMaterialShell-${DMS_VERSION}" @@ -709,10 +800,17 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t echo " - OpenSUSE source tarballs created" fi - # Copy and update OpenSUSE spec file with the correct version (for -git packages) + # Copy and update OpenSUSE spec file with the correct version cp "distro/opensuse/$PACKAGE.spec" "$WORK_DIR/" if [[ "$PACKAGE" == *"-git" ]] && [[ -n "$CHANGELOG_VERSION" ]]; then update_opensuse_git_spec "$WORK_DIR/$PACKAGE.spec" + elif [[ "$PACKAGE" == "dms-greeter" ]] && [[ -n "$CHANGELOG_VERSION" ]]; then + DMS_GREETER_BASE_VERSION=$(echo "$CHANGELOG_VERSION" | sed -E 's/^([0-9]+(\.[0-9]+)*).*/\1/') + DMS_GREETER_RELEASE=$(echo "$CHANGELOG_VERSION" | sed -E 's/.*db([0-9]+)$/\1/' || echo "1") + CHANGELOG_DATE=$(date '+%a %b %d %Y') + sed -i "s/VERSION_PLACEHOLDER/${DMS_GREETER_BASE_VERSION}/g" "$WORK_DIR/$PACKAGE.spec" + sed -i "s/RELEASE_PLACEHOLDER/${DMS_GREETER_RELEASE}/g" "$WORK_DIR/$PACKAGE.spec" + sed -i "s/CHANGELOG_DATE_PLACEHOLDER/${CHANGELOG_DATE}/g" "$WORK_DIR/$PACKAGE.spec" fi fi @@ -839,8 +937,48 @@ EOF echo " - Quilt format detected: creating debian.tar.gz" tar -czf "$WORK_DIR/debian.tar.gz" -C "distro/debian/$PACKAGE" debian/ + # For dms-greeter: create orig tarball so Debian build gets upstream (OBS only passes .dsc Files to Debian) + DSC_FILES_DEBIAN="" + if [[ "$PACKAGE" == "dms-greeter" ]]; then + UPSTREAM_VER=$(echo "$VERSION" | sed 's/-[^-]*$//') + ORIG_TARBALL="${PACKAGE}_${UPSTREAM_VER}.orig.tar.gz" + ORIG_DIR="${PACKAGE}-${UPSTREAM_VER}" + + if [[ -f "distro/debian/$PACKAGE/_service" ]] && grep -q "download_url" "distro/debian/$PACKAGE/_service"; then + DG_TEMP=$(mktemp -d) + DMS_GREETER_PATH=$(grep -A 5 'name="download_url"' "distro/debian/$PACKAGE/_service" | grep "path" | sed 's/.*\(.*\)<\/param>.*/\1/' | head -1) + if [[ -n "$DMS_GREETER_PATH" ]]; then + DG_URL="https://github.com${DMS_GREETER_PATH}" + echo " - Downloading dms-greeter source for orig tarball: $DG_URL" + if wget -q -O "$DG_TEMP/dms-qml.tar.gz" "$DG_URL" 2>/dev/null || curl -L -f -s -o "$DG_TEMP/dms-qml.tar.gz" "$DG_URL" 2>/dev/null; then + ( cd "$DG_TEMP" && tar --no-same-owner -xzf dms-qml.tar.gz && mkdir -p "$ORIG_DIR" && \ + for f in *; do [[ "$f" != "dms-qml.tar.gz" && "$f" != "$ORIG_DIR" ]] && mv "$f" "$ORIG_DIR/"; done ) + if [[ -d "$DG_TEMP/$ORIG_DIR/Modules" ]] || [[ -f "$DG_TEMP/$ORIG_DIR/LICENSE" ]]; then + tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$ORIG_TARBALL" -C "$DG_TEMP" "$ORIG_DIR" + ORIG_MD5=$(md5sum "$WORK_DIR/$ORIG_TARBALL" | cut -d' ' -f1) + ORIG_SIZE=$(stat -c%s "$WORK_DIR/$ORIG_TARBALL" 2>/dev/null || stat -f%z "$WORK_DIR/$ORIG_TARBALL" 2>/dev/null) + DSC_FILES_DEBIAN=" $ORIG_MD5 $ORIG_SIZE $ORIG_TARBALL +" + echo " - Created $ORIG_TARBALL for Debian orig" + fi + rm -rf "$DG_TEMP" + fi + fi + fi + fi + + DEBIAN_MD5=$(md5sum "$WORK_DIR/debian.tar.gz" | cut -d' ' -f1) + DEBIAN_SIZE=$(stat -c%s "$WORK_DIR/debian.tar.gz" 2>/dev/null || stat -f%z "$WORK_DIR/debian.tar.gz" 2>/dev/null) + echo " - Generating $PACKAGE.dsc for quilt format" - cat >"$WORK_DIR/$PACKAGE.dsc" <"$WORK_DIR/$PACKAGE.dsc" < Build-Depends: debhelper-compat (= 13), wget, gzip -DEBTRANSFORM-TAR: debian.tar.gz -Files: - 00000000000000000000000000000000 1 debian.tar.gz -EOF +${DEBTRANSFORM_EXTRA}Files:${DSC_FILES_DEBIAN} + $DEBIAN_MD5 $DEBIAN_SIZE debian.tar.gz +DSCEOF fi fi fi @@ -882,6 +1019,13 @@ if [[ -n "$OBS_FILES" ]]; then continue fi + # Keep current orig tarball for dms-greeter (Debian 3.0 quilt needs it) + UPSTREAM_VER_CLEAN=$(echo "$CHANGELOG_VERSION" | sed 's/-[^-]*$//' 2>/dev/null) + if [[ "$PACKAGE" == "dms-greeter" ]] && [[ "$old_file" == "${PACKAGE}_${UPSTREAM_VER_CLEAN}.orig.tar.gz" ]]; then + echo " - Keeping orig tarball: $old_file" + continue + fi + if [[ "$old_file" == "${PACKAGE}-source.tar.gz" ]]; then echo " - Keeping source tarball: $old_file" continue diff --git a/quickshell/Modules/Greetd/README.md b/quickshell/Modules/Greetd/README.md index 8e650d88..762ca587 100644 --- a/quickshell/Modules/Greetd/README.md +++ b/quickshell/Modules/Greetd/README.md @@ -7,7 +7,7 @@ A greeter for [greetd](https://github.com/kennylevinsen/greetd) that follows the - **Multi user**: Login with any system user - **dms sync**: Sync settings with dms for consistent styling between shell and greeter - **Multiple compositors**: Supports niri, Hyprland, Sway, or mangowc. -- **Custom PAM**: Supports custom PAM configuration in `/etc/pam.d/dankshell` +- **Custom PAM**: Supports custom PAM configuration in `/etc/pam.d/greetd` - **Session Memory**: Remembers last selected session and user ## Installation @@ -22,11 +22,32 @@ paru -S greetd-dms-greeter-git yay -S greetd-dms-greeter-git ``` -Once installed, disable any existing display manager and enable greetd: +### Debian / openSUSE + +Official packages are available from the [DankLinux OBS repository](https://software.opensuse.org/download/package?package=dms-greeter&project=home%3AAvengeMedia%3Adanklinux). Add the repo for your distribution and install: ```bash -sudo systemctl disable gdm sddm lightdm -sudo systemctl enable greetd +# Debian 13 +sudo apt install dms-greeter # after adding the repo + +# openSUSE Tumbleweed +zypper install dms-greeter # after adding the repo +``` + +See the [Installation guide](https://danklinux.com/docs/dankgreeter/installation) for full repository setup. + +If you previously installed manually, remove legacy files first: + +```bash +sudo rm -f /usr/local/bin/dms-greeter +sudo rm -rf /etc/xdg/quickshell/dms-greeter +``` + +Then complete setup: + +```bash +dms greeter enable +dms greeter sync ``` #### Syncing themes (Optional) @@ -79,43 +100,32 @@ The package automatically: - Sets up directories and permissions - Configures greetd with auto-detected compositor - Applies SELinux contexts -- Installs the `dms-greeter-sync` helper script -Then disable existing display manager and enable greetd: +Then complete setup: ```bash -sudo systemctl disable gdm sddm lightdm -sudo systemctl enable greetd +dms greeter enable +dms greeter sync ``` #### Syncing themes (Optional) -The RPM package includes the `dms-greeter-sync` helper for easy theme syncing: +Run: ```bash -dms-greeter-sync +dms greeter sync ``` -Then logout/login to see your wallpaper on the greeter! - -
-What does dms-greeter-sync do? - -The `dms-greeter-sync` helper automatically: -- Adds you to the greeter group -- Sets minimal ACL permissions on parent directories (traverse only) -- Sets group ownership on your DMS config directories -- Creates symlinks to share your theme files with the greeter - -This uses standard Linux ACLs (Access Control Lists) - the same security model used by GNOME, KDE, and systemd. The greeter user only gets traverse permission through your directories and can only read the specific theme files you share. - -
+Then logout/login to see your wallpaper on the greeter. ### Automatic The easiest thing is to run `dms greeter install` or `dms` for interactive installation. +On Debian/openSUSE, this now prefers the `dms-greeter` package when the OBS repo is configured. -### Manual +### Manual (fallback only) + +Use this only if no package is available for your distro. 1. Install `greetd` (in most distro's standard repositories) and `quickshell` @@ -211,7 +221,7 @@ vt = 1 [default_session] user = "greeter" -command = "/usr/local/bin/dms-greeter --command niri" +command = "/usr/bin/dms-greeter --command niri" ``` ### Manual usage @@ -234,7 +244,7 @@ Simply edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` to change The greeter can be personalized with wallpapers, themes, weather, clock formats, and more - configured exactly the same as dms. -**Easiest method:** Run `dms-greeter-sync` to automatically sync your DMS theme with the greeter. +**Easiest method:** Run `dms greeter sync` to automatically sync your DMS theme with the greeter. **Manual method:** You can manually synchronize configurations if you want greeter settings to always mirror your shell: diff --git a/quickshell/Modules/Greetd/assets/dms-greeter b/quickshell/Modules/Greetd/assets/dms-greeter index 7a5cfdcd..4b1597fc 100755 --- a/quickshell/Modules/Greetd/assets/dms-greeter +++ b/quickshell/Modules/Greetd/assets/dms-greeter @@ -35,6 +35,14 @@ Examples: EOF } +require_command() { + local cmd="$1" + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "Error: required command '$cmd' was not found in PATH" >&2 + exit 1 + fi +} + while [[ $# -gt 0 ]]; do case $1 in --command) @@ -107,14 +115,23 @@ export DMS_GREET_CFG_DIR="$CACHE_DIR" mkdir -p "$CACHE_DIR" -QS_CMD="qs" +if command -v qs >/dev/null 2>&1; then + QS_BIN="qs" +elif command -v quickshell >/dev/null 2>&1; then + QS_BIN="quickshell" +else + echo "Error: neither 'qs' nor 'quickshell' was found in PATH" >&2 + exit 1 +fi + +QS_CMD="$QS_BIN" if [[ "$DMS_PATH" == /* ]]; then - QS_CMD="qs -p $DMS_PATH" + QS_CMD="$QS_BIN -p $DMS_PATH" else RESOLVED_PATH=$(locate_dms_config "$DMS_PATH") if [[ $? -eq 0 && -n "$RESOLVED_PATH" ]]; then echo "Located DMS config at: $RESOLVED_PATH" >&2 - QS_CMD="qs -p $RESOLVED_PATH" + QS_CMD="$QS_BIN -p $RESOLVED_PATH" else echo "Error: Could not find DMS config '$DMS_PATH' (shell.qml) in any valid config path" >&2 exit 1 @@ -123,6 +140,7 @@ fi case "$COMPOSITOR" in niri) + require_command "niri" if [[ -z "$COMPOSITOR_CONFIG" ]]; then TEMP_CONFIG=$(mktemp) # base/default config @@ -178,6 +196,10 @@ NIRI_EOF ;; hyprland) + if ! command -v start-hyprland >/dev/null 2>&1 && ! command -v Hyprland >/dev/null 2>&1; then + echo "Error: neither 'start-hyprland' nor 'Hyprland' was found in PATH" >&2 + exit 1 + fi if [[ -z "$COMPOSITOR_CONFIG" ]]; then TEMP_CONFIG=$(mktemp) cat > "$TEMP_CONFIG" << HYPRLAND_EOF @@ -207,6 +229,7 @@ HYPRLAND_EOF ;; sway) + require_command "sway" if [[ -z "$COMPOSITOR_CONFIG" ]]; then TEMP_CONFIG=$(mktemp) cat > "$TEMP_CONFIG" << SWAY_EOF @@ -226,6 +249,7 @@ SWAY_EOF ;; scroll) + require_command "scroll" if [[ -z "$COMPOSITOR_CONFIG" ]]; then TEMP_CONFIG=$(mktemp) cat > "$TEMP_CONFIG" << SCROLL_EOF @@ -245,6 +269,7 @@ SCROLL_EOF ;; miracle|miracle-wm) + require_command "miracle-wm" if [[ -z "$COMPOSITOR_CONFIG" ]]; then TEMP_CONFIG=$(mktemp) cat > "$TEMP_CONFIG" << MIRACLE_EOF @@ -264,6 +289,7 @@ MIRACLE_EOF ;; labwc) + require_command "labwc" if [[ -n "$COMPOSITOR_CONFIG" ]]; then exec labwc --config "$COMPOSITOR_CONFIG" --session "$QS_CMD" else @@ -272,6 +298,7 @@ MIRACLE_EOF ;; mango|mangowc) + require_command "mango" if [[ -n "$COMPOSITOR_CONFIG" ]]; then exec mango -c "$COMPOSITOR_CONFIG" -s "$QS_CMD && mmsg -d quit" else