feat: switch to /usr layout and add dynamic dependency detection
All checks were successful
Build and Release Zed Editor / check-version (push) Successful in 3s
Build and Release Zed Editor / build-and-release (push) Successful in 1m21s

- Move binaries to /usr/bin and /usr/libexec for system integration
- Add find-deps.sh script to detect required system packages from .so
  files
- Update Makefile to generate Depends field dynamically using apt-file
- Add list-deps target to Makefile for dependency analysis
- Update README with new usage, features, and instructions
- Update CI workflow to install apt-file and update its database
This commit is contained in:
2025-10-14 11:46:28 +02:00
parent 260cff501a
commit 0dba8ae99a
6 changed files with 370 additions and 144 deletions

View File

@@ -6,7 +6,7 @@ on:
- main
schedule:
# Check daily at 2 AM for new versions
- cron: '0 2 * * *'
- cron: "0 2 * * *"
workflow_dispatch:
# Allow manual triggering
@@ -56,7 +56,11 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y wget curl jq dpkg-dev
sudo apt-get install -y wget curl jq dpkg-dev apt-file
- name: Update apt-file database
run: |
sudo apt-file update
- name: Build DEB package
run: |

115
Makefile
View File

@@ -1,4 +1,4 @@
.PHONY: all clean download extract deb help
.PHONY: all clean download extract deb help list-deps
# Variables
GITHUB_REPO = zed-industries/zed
@@ -8,6 +8,7 @@ BUILD_DIR = build
EXTRACT_DIR = $(BUILD_DIR)/extracted
DEB_DIR = $(BUILD_DIR)/deb
CONTROL_DIR = $(DEB_DIR)/DEBIAN
FIND_DEPS_SCRIPT = ./find-deps.sh
# Determine the latest stable version
VERSION := $(shell curl -s https://api.github.com/repos/$(GITHUB_REPO)/releases/latest | jq -r '.tag_name' | sed 's/^v//')
@@ -20,15 +21,16 @@ DEB_FILE = $(BUILD_DIR)/$(PACKAGE_NAME)_$(VERSION)_amd64.deb
all: deb
help:
@echo "Makefile to create a .deb package for Zed Editor"
@echo "Makefile to create a .deb package for Zed Editor (using /usr layout)"
@echo ""
@echo "Available targets:"
@echo " all - Build the .deb package (default target)"
@echo " download - Download the archive from GitHub"
@echo " extract - Extract the archive"
@echo " deb - Create the .deb package"
@echo " clean - Clean up temporary files"
@echo " help - Display this help"
@echo " all - Build the .deb package (default target)"
@echo " download - Download the archive from GitHub"
@echo " extract - Extract the archive"
@echo " deb - Create the .deb package"
@echo " list-deps - List dynamic library dependencies"
@echo " clean - Clean up temporary files"
@echo " help - Display this help"
@echo ""
@echo "Detected version: $(VERSION)"
@@ -55,75 +57,76 @@ $(EXTRACT_DIR)/.extracted: $(BUILD_DIR)/$(ARCHIVE_NAME)
@touch $@
@echo "Extraction complete"
# List dependencies dynamically
list-deps: $(EXTRACT_DIR)/.extracted
@echo "Analyzing library dependencies..."
@chmod +x $(FIND_DEPS_SCRIPT)
@$(FIND_DEPS_SCRIPT) $(EXTRACT_DIR)/zed.app/lib
# Create the .deb package
deb: $(DEB_FILE)
$(DEB_FILE): $(EXTRACT_DIR)/.extracted
@echo "Building .deb package..."
@echo "Building .deb package with /usr layout..."
@mkdir -p $(CONTROL_DIR)
@mkdir -p $(DEB_DIR)/opt/zed
@mkdir -p $(DEB_DIR)/usr/bin
@mkdir -p $(DEB_DIR)/usr/libexec
@mkdir -p $(DEB_DIR)/usr/share/applications
@mkdir -p $(DEB_DIR)/usr/share/icons/hicolor/512x512/apps
@mkdir -p $(DEB_DIR)/usr/share/icons/hicolor/1024x1024/apps
@mkdir -p $(DEB_DIR)/usr/share/doc/zed-editor
# Copy application files
@echo "Copying files..."
@cp -r $(EXTRACT_DIR)/zed.app/* $(DEB_DIR)/opt/zed/
# Create symbolic link for the binary
@ln -sf /opt/zed/bin/zed $(DEB_DIR)/usr/bin/zed
# Copy application files (excluding bundled libraries)
@echo "Copying binaries..."
@cp $(EXTRACT_DIR)/zed.app/bin/zed $(DEB_DIR)/usr/bin/
@cp $(EXTRACT_DIR)/zed.app/libexec/zed-editor $(DEB_DIR)/usr/libexec/
# Copy desktop file and icons
@echo "Copying desktop files and icons..."
@cp $(EXTRACT_DIR)/zed.app/share/applications/zed.desktop $(DEB_DIR)/usr/share/applications/
@sed -i '/^\[Desktop Entry\]/a StartupWMClass=dev.zed.Zed' $(DEB_DIR)/usr/share/applications/zed.desktop
@cp $(EXTRACT_DIR)/zed.app/share/icons/hicolor/512x512/apps/zed.png $(DEB_DIR)/usr/share/icons/hicolor/512x512/apps/
@cp $(EXTRACT_DIR)/zed.app/share/icons/hicolor/1024x1024/apps/zed.png $(DEB_DIR)/usr/share/icons/hicolor/1024x1024/apps/
# Create control file
@echo "Package: $(PACKAGE_NAME)" > $(CONTROL_DIR)/control
@echo "Version: $(VERSION)" >> $(CONTROL_DIR)/control
@echo "Section: editors" >> $(CONTROL_DIR)/control
@echo "Priority: optional" >> $(CONTROL_DIR)/control
@echo "Architecture: amd64" >> $(CONTROL_DIR)/control
@echo "Maintainer: Zed Packager <packager@local>" >> $(CONTROL_DIR)/control
@echo "Description: Zed - A high-performance, multiplayer code editor" >> $(CONTROL_DIR)/control
@echo " Zed is a next-generation code editor designed for" >> $(CONTROL_DIR)/control
@echo " high-performance collaboration with humans and AI." >> $(CONTROL_DIR)/control
@echo "Homepage: https://zed.dev" >> $(CONTROL_DIR)/control
# Copy licenses
@cp $(EXTRACT_DIR)/zed.app/licenses.md $(DEB_DIR)/usr/share/doc/zed-editor/
# Create postinst script to update icon cache
@echo "#!/bin/sh" > $(CONTROL_DIR)/postinst
@echo "set -e" >> $(CONTROL_DIR)/postinst
@echo "if [ \"\$$1\" = \"configure\" ] || [ \"\$$1\" = \"abort-upgrade\" ] || [ \"\$$1\" = \"abort-deconfigure\" ] || [ \"\$$1\" = \"abort-remove\" ]; then" >> $(CONTROL_DIR)/postinst
@echo " if command -v gtk-update-icon-cache >/dev/null 2>&1; then" >> $(CONTROL_DIR)/postinst
@echo " gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor || true" >> $(CONTROL_DIR)/postinst
@echo " fi" >> $(CONTROL_DIR)/postinst
@echo " if command -v update-desktop-database >/dev/null 2>&1; then" >> $(CONTROL_DIR)/postinst
@echo " update-desktop-database -q /usr/share/applications || true" >> $(CONTROL_DIR)/postinst
@echo " fi" >> $(CONTROL_DIR)/postinst
@echo "fi" >> $(CONTROL_DIR)/postinst
@echo "exit 0" >> $(CONTROL_DIR)/postinst
# Create control file with library dependencies
@echo "Creating control file with dependencies..."
@chmod +x $(FIND_DEPS_SCRIPT)
@echo "Detecting library dependencies..."
@DEPS=$$($(FIND_DEPS_SCRIPT) --quiet --format makefile $(EXTRACT_DIR)/zed.app/lib); \
echo "Package: $(PACKAGE_NAME)" > $(CONTROL_DIR)/control; \
echo "Version: $(VERSION)" >> $(CONTROL_DIR)/control; \
echo "Section: editors" >> $(CONTROL_DIR)/control; \
echo "Priority: optional" >> $(CONTROL_DIR)/control; \
echo "Architecture: amd64" >> $(CONTROL_DIR)/control; \
if [ -n "$$DEPS" ]; then \
echo "Depends: $$DEPS" >> $(CONTROL_DIR)/control; \
echo " Detected dependencies: $$DEPS"; \
else \
echo "Depends: libc6" >> $(CONTROL_DIR)/control; \
echo " Warning: Could not detect dependencies, using minimal set"; \
fi; \
echo "Maintainer: Zed Packager <packager@local>" >> $(CONTROL_DIR)/control; \
echo "Description: Zed - A high-performance, multiplayer code editor" >> $(CONTROL_DIR)/control; \
echo " Zed is a next-generation code editor designed for" >> $(CONTROL_DIR)/control; \
echo " high-performance collaboration with humans and AI." >> $(CONTROL_DIR)/control; \
echo " ." >> $(CONTROL_DIR)/control; \
echo " This package uses system libraries instead of bundled ones." >> $(CONTROL_DIR)/control; \
echo "Homepage: https://zed.dev" >> $(CONTROL_DIR)/control
# Create postrm script to update icon cache on removal
@echo "#!/bin/sh" > $(CONTROL_DIR)/postrm
@echo "set -e" >> $(CONTROL_DIR)/postrm
@echo "if [ \"\$$1\" = \"remove\" ] || [ \"\$$1\" = \"purge\" ]; then" >> $(CONTROL_DIR)/postrm
@echo " if command -v gtk-update-icon-cache >/dev/null 2>&1; then" >> $(CONTROL_DIR)/postrm
@echo " gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor || true" >> $(CONTROL_DIR)/postrm
@echo " fi" >> $(CONTROL_DIR)/postrm
@echo " if command -v update-desktop-database >/dev/null 2>&1; then" >> $(CONTROL_DIR)/postrm
@echo " update-desktop-database -q /usr/share/applications || true" >> $(CONTROL_DIR)/postrm
@echo " fi" >> $(CONTROL_DIR)/postrm
@echo "fi" >> $(CONTROL_DIR)/postrm
@echo "exit 0" >> $(CONTROL_DIR)/postrm
# Copy maintainer scripts
@echo "Creating maintainer scripts..."
@cp postinst $(CONTROL_DIR)/postinst
@cp postrm $(CONTROL_DIR)/postrm
# Set permissions
@chmod 755 $(DEB_DIR)/opt/zed/bin/zed
@chmod 755 $(DEB_DIR)/opt/zed/libexec/zed-editor
@echo "Setting permissions..."
@chmod 755 $(DEB_DIR)/usr/bin/zed
@chmod 755 $(DEB_DIR)/usr/libexec/zed-editor
@chmod 755 $(CONTROL_DIR)/postinst
@chmod 755 $(CONTROL_DIR)/postrm
@find $(DEB_DIR)/opt/zed/lib -type f -name "*.so*" -exec chmod 644 {} \;
# Build the .deb package
@echo "Creating .deb package..."
@@ -131,7 +134,11 @@ $(DEB_FILE): $(EXTRACT_DIR)/.extracted
@echo ""
@echo "✓ Package successfully created: $(DEB_FILE)"
@echo ""
@echo "Dependencies were automatically detected from bundled libraries."
@echo "Run 'make list-deps' to see the full dependency analysis."
@echo ""
@echo "To install: sudo dpkg -i $(DEB_FILE)"
@echo "If dependencies are missing: sudo apt-get install -f"
# Clean up
clean:

172
README.md
View File

@@ -1,122 +1,118 @@
# Zed Editor Packager
# Zed Packager
Automated packaging system for [Zed Editor](https://zed.dev/) for Debian/Ubuntu.
## Description
This project automatically creates `.deb` packages of Zed Editor from official GitHub releases and publishes them to a Gitea repository.
A Makefile-based tool to package Zed editor as a Debian/Ubuntu package with dynamic dependency detection.
## Features
- **Automatic version detection**: Fetches the latest stable version from GitHub
- **DEB package building**: Creates a ready-to-install Debian package
- **CI/CD with Gitea Actions**: Automated workflow that:
- Checks daily for new versions
- Builds the package only if a new version is available
- Creates a Gitea release with the package
- Publishes the package to the Gitea Debian repository
- **Automatic downloads** latest Zed release from GitHub
- **Dynamic dependency detection** using `apt-file` to find required system packages
- **System libraries** instead of bundled libraries for better integration
- **Proper installation** with maintainer scripts for icon cache updates
## Local Usage
### Prerequisites
## Prerequisites
```bash
sudo apt-get install wget curl jq dpkg-dev
sudo apt install wget jq dpkg-dev apt-file
sudo apt-file update
```
### Manual Building
## Usage
### Build the package
```bash
# Build the package
make
```
# Or step by step
make download # Download the archive
make extract # Extract the archive
make deb # Create the .deb package
This will:
1. Download the latest Zed release
2. Extract the archive
3. Analyze bundled libraries to detect system dependencies
4. Create a `.deb` package with dynamic dependencies
# Clean up
### List dependencies
To see what system packages are needed:
```bash
make list-deps
```
This will show a detailed analysis of each `.so` library and its corresponding Debian/Ubuntu package.
### Install the package
```bash
sudo dpkg -i build/zed-editor_*.deb
sudo apt-get install -f # Install missing dependencies if any
```
### Clean up
```bash
make clean
```
### Installation
## How it works
### Dynamic Dependency Detection
The `find-deps.sh` script analyzes the `.so` files bundled with Zed and uses `apt-file` to find the corresponding Debian/Ubuntu packages. This ensures dependencies are always up-to-date.
**Script usage:**
```bash
# Install the locally created package
sudo dpkg -i build/zed-editor_*.deb
# Human-readable output
./find-deps.sh /path/to/zed.app/lib
# Machine-readable formats
./find-deps.sh --format makefile /path/to/zed.app/lib # Comma-separated
./find-deps.sh --format list /path/to/zed.app/lib # One per line
# Quiet mode (no progress messages)
./find-deps.sh --quiet --format makefile /path/to/zed.app/lib
```
## Gitea Workflow
### Makefile Integration
The [`.gitea/workflows/build-and-release.yml`](.gitea/workflows/build-and-release.yml) workflow runs:
The Makefile automatically calls `find-deps.sh` during package creation to generate the `Depends:` field in the control file. This means:
- **Automatically**: Every day at 2 AM (cron)
- **Manually**: Via the Gitea interface (workflow_dispatch)
- **On push**: On every push to the `main` branch
- ✅ Dependencies are always detected from actual bundled libraries
- ✅ Works with any Zed version
- ✅ No manual maintenance required
### Required Configuration
To publish to the Gitea Debian repository, create a `PACKAGE_PUB_TOKEN` secret:
1. Generate a personal access token on Gitea with package permissions
2. Add it as a secret in the repository settings: `PACKAGE_PUB_TOKEN`
### Workflow Behavior
1. **Version check**: Compares the latest GitHub version with the latest Gitea release
2. **Early exit**: If versions match, the workflow stops immediately
3. **Build**: If a new version is detected, builds the .deb package
4. **Publishing**:
- Creates a Gitea release with the version tag
- Uploads the .deb file to the release assets
- Publishes the package to the Gitea Debian repository
## Package Structure
The package installs Zed in the following locations:
## Project Structure
```
/opt/zed/ # Main application
/opt/zed/bin/zed # Main binary
/opt/zed/libexec/zed-editor # Editor binary
/opt/zed/lib/ # Shared libraries
/usr/bin/zed # Symbolic link
/usr/share/applications/zed.desktop # Desktop file
/usr/share/icons/hicolor/*/apps/zed.png # Icons
.
├── Makefile # Main build system
├── find-deps.sh # Dynamic dependency detection script
└── build/
├── extracted/ # Extracted Zed archive
├── deb/ # Package staging directory
└── zed-editor_*.deb # Final package
```
## Installation from Gitea Repository
## Available Make Targets
Once the repository is configured:
| Target | Description |
|--------------|------------------------------------------|
| `all` | Build the .deb package (default) |
| `download` | Download the archive from GitHub |
| `extract` | Extract the archive |
| `deb` | Create the .deb package |
| `list-deps` | List dynamic library dependencies |
| `clean` | Clean up temporary files |
| `help` | Display help |
```bash
# Add the repository (adapt according to your Gitea instance)
echo "deb https://git.rawleenc.dev/api/packages/YOUR_USERNAME/debian stable main" | sudo tee /etc/apt/sources.list.d/zed-editor.list
## Package Details
# Install
sudo apt update
sudo apt install zed-editor
```
## Makefile
The Makefile supports the following targets:
| Target | Description |
|------------|---------------------------------------------|
| `all` | Build the complete package (default target) |
| `download` | Download the archive from GitHub |
| `extract` | Extract the archive |
| `deb` | Create the .deb package |
| `clean` | Clean up temporary files |
| `help` | Display help |
- **Package name:** `zed-editor`
- **Installation location:** `/usr/bin/zed`, `/usr/libexec/zed-editor`
- **Desktop integration:** Yes (with proper window class binding)
- **Icon cache:** Automatically updated via maintainer scripts
- **Dependencies:** Dynamically detected from bundled libraries
## License
This project is a packaging tool. Zed Editor itself is subject to its own license.
## Notes
- The created packages are **unofficial**
- Binaries come directly from official Zed releases
- The packaging only adds system integration (desktop files, etc.)
This packaging tool is provided as-is. Zed editor is subject to its own license terms.

197
find-deps.sh Executable file
View File

@@ -0,0 +1,197 @@
#!/bin/bash
# Script to find Debian/Ubuntu packages corresponding to zed.app .so files
# Requires apt-file (install with: sudo apt install apt-file && sudo apt-file update)
set -e
# Colors for display
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Parse arguments
QUIET=0
OUTPUT_FORMAT="human"
ZED_LIB_DIR=""
while [[ $# -gt 0 ]]; do
case $1 in
-q|--quiet)
QUIET=1
shift
;;
--format)
OUTPUT_FORMAT="$2"
shift 2
;;
-h|--help)
echo "Usage: $0 [OPTIONS] [LIBRARY_DIR]"
echo ""
echo "Options:"
echo " -q, --quiet Suppress progress messages"
echo " --format FORMAT Output format: human, makefile, list (default: human)"
echo " -h, --help Show this help"
echo ""
echo "Output formats:"
echo " human - Colored, verbose output with summary"
echo " makefile - Comma-separated list suitable for Makefile Depends field"
echo " list - One package per line"
exit 0
;;
*)
ZED_LIB_DIR="$1"
shift
;;
esac
done
# Default path if not provided
ZED_LIB_DIR="${ZED_LIB_DIR:-./build/extracted/zed.app/lib}"
# Disable colors in quiet mode or non-human formats
if [ "$QUIET" -eq 1 ] || [ "$OUTPUT_FORMAT" != "human" ]; then
RED=''
GREEN=''
YELLOW=''
BLUE=''
NC=''
fi
# Check if apt-file is installed
if ! command -v apt-file &> /dev/null; then
if [ "$QUIET" -eq 0 ]; then
echo -e "${RED}Error: apt-file is not installed${NC}" >&2
echo "Install it with: sudo apt install apt-file" >&2
echo "Then update the database: sudo apt-file update" >&2
fi
exit 1
fi
# Check if directory exists
if [ ! -d "$ZED_LIB_DIR" ]; then
if [ "$QUIET" -eq 0 ]; then
echo -e "${RED}Error: Directory $ZED_LIB_DIR does not exist${NC}" >&2
fi
exit 1
fi
# Human format: show header
if [ "$OUTPUT_FORMAT" = "human" ] && [ "$QUIET" -eq 0 ]; then
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
echo -e "${BLUE} Finding packages for Zed dependencies${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
echo ""
echo -e "Analyzing directory: ${YELLOW}$ZED_LIB_DIR${NC}"
echo ""
fi
# Counters
total=0
found=0
not_found=0
# Array to store results
declare -A packages
# Iterate through all .so files
for lib in "$ZED_LIB_DIR"/*.so*; do
if [ -f "$lib" ]; then
lib_name=$(basename "$lib")
total=$((total + 1))
if [ "$OUTPUT_FORMAT" = "human" ] && [ "$QUIET" -eq 0 ]; then
echo -e "${YELLOW}[$total]${NC} Searching for: ${GREEN}$lib_name${NC}"
fi
# Search for package with apt-file
# Look for the file name in /usr/lib or /lib
result=$(apt-file search "/$lib_name" 2>/dev/null | grep -E '(/usr/lib|/lib)' | head -n 1)
if [ -n "$result" ]; then
# Extract package name (before first :)
package=$(echo "$result" | cut -d':' -f1)
if [ "$OUTPUT_FORMAT" = "human" ] && [ "$QUIET" -eq 0 ]; then
echo -e " → Package found: ${GREEN}$package${NC}"
fi
packages["$package"]=1
found=$((found + 1))
else
if [ "$OUTPUT_FORMAT" = "human" ] && [ "$QUIET" -eq 0 ]; then
echo -e "${RED}No package found${NC}"
fi
not_found=$((not_found + 1))
fi
if [ "$OUTPUT_FORMAT" = "human" ] && [ "$QUIET" -eq 0 ]; then
echo ""
fi
fi
done
# Output based on format
case "$OUTPUT_FORMAT" in
makefile)
# Comma-separated list for Makefile Depends field
first=1
for pkg in "${!packages[@]}"; do
if [ $first -eq 1 ]; then
echo -n "$pkg"
first=0
else
echo -n ", $pkg"
fi
done
echo ""
;;
list)
# One package per line, sorted
for pkg in "${!packages[@]}"; do
echo "$pkg"
done | sort
;;
human)
# Summary
if [ "$QUIET" -eq 0 ]; then
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
echo -e "${BLUE} SUMMARY${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
echo -e "Total libraries analyzed: ${YELLOW}$total${NC}"
echo -e "Packages found: ${GREEN}$found${NC}"
echo -e "Not found: ${RED}$not_found${NC}"
echo ""
fi
# Unique package list
if [ ${#packages[@]} -gt 0 ]; then
if [ "$QUIET" -eq 0 ]; then
echo -e "${GREEN}Required unique packages:${NC}"
fi
for pkg in "${!packages[@]}"; do
echo -e " - $pkg"
done
if [ "$QUIET" -eq 0 ]; then
echo ""
echo -e "${BLUE}Installation command:${NC}"
install_cmd="sudo apt install"
for pkg in "${!packages[@]}"; do
install_cmd="$install_cmd $pkg"
done
echo -e "${GREEN}$install_cmd${NC}"
fi
fi
;;
esac
exit 0

11
postinst Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
set -e
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ]; then
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor || true
fi
if command -v update-desktop-database >/dev/null 2>&1; then
update-desktop-database -q /usr/share/applications || true
fi
fi
exit 0

11
postrm Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
set -e
if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor || true
fi
if command -v update-desktop-database >/dev/null 2>&1; then
update-desktop-database -q /usr/share/applications || true
fi
fi
exit 0