mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 45e4053883 | |||
| c0b617f4f1 | |||
| a28cfd284b | |||
| a5b9cb69bd | |||
| 3c8f252a14 | |||
| 8a63818f31 | |||
| 5b5e26e529 | |||
| 866769c054 | |||
| 2e3b71f5f1 | |||
| 1312d61141 | |||
| f7867cf6ca | |||
| 2ca6887a5d | |||
| 368685f8cd | |||
| ad2d192b94 | |||
| 3214e94cdb | |||
| 37c537379d | |||
| 3c01c5f085 | |||
| 4c552bb8ca | |||
| ce73d29855 | |||
| d6e314744b | |||
| ec603188de | |||
| fbf48addc7 | |||
| cbf726580f | |||
| 28f258fc8c | |||
| 8b3acfd770 | |||
| a581e8de01 | |||
| 7c74db5e74 | |||
| b17b4235f3 | |||
| ec3564e8aa | |||
| 9a887ac04b | |||
| fed808a3c6 | |||
| 37983b33a2 | |||
| 1b2224fac6 | |||
| c1c165ab48 | |||
| 68bea1816f | |||
| cb7875e479 | |||
| 910a3182f7 | |||
| 05886f8dcb | |||
| cff3c27729 | |||
| 80be2ca22c | |||
| d133b6c0c3 | |||
| a3592bd3b7 | |||
| 70e8e96302 | |||
| 6002edccd3 | |||
| d189004d65 | |||
| 26b700bf51 | |||
| 09f24745c3 | |||
| 7ffbbe6890 | |||
| ad94c112fe | |||
| 8c7cc68cbf | |||
| dc047b635f | |||
| cc4c2fed25 | |||
| 17e47ecd6d | |||
| b1d5ff477b | |||
| d6dc01ac2c | |||
| 77ebe0d02f | |||
| 81e3d4c905 | |||
| cb8f36444c | |||
| 799def70dc | |||
| 20f741d0e5 | |||
| d38f4a24f2 | |||
| 6604cc4df9 | |||
| 89aa4d1eae | |||
| 9231ea5114 | |||
| 4a3c72338d | |||
| ab862f4383 | |||
| bd43be931a | |||
| 148240cbbb | |||
| 2e9e42d9ae | |||
| 89fbda0d6e | |||
| c97eb5c889 | |||
| 366ec46b26 | |||
| 62a98ebc71 | |||
| 439c605efe | |||
| 32df2f3487 | |||
| 692da7ffc2 | |||
| 1082b24b1d | |||
| f45ceedb8a | |||
| d614e43981 | |||
| 1e0e7a31aa | |||
| 92fffe9c82 | |||
| 11e51300a5 | |||
| ef84e1bb02 | |||
| 1887d58df8 | |||
| c66f6f8900 | |||
| 902fe7b7ab | |||
| 472e1fee17 | |||
| 3c6f2d07e0 | |||
| 43254aa396 | |||
| 48ebf86335 | |||
| f1e3b4907e | |||
| 9346a0d05e | |||
| c99faae115 | |||
| a5aa68ee8d | |||
| 8959ac06ac | |||
| 47f7ebfd68 | |||
| 7d91f218b1 | |||
| e5e2db37d9 | |||
| e08ea3b9e5 | |||
| 4f1907abfa | |||
| 92d74c293e | |||
| 3fbdced0e1 |
@@ -61,14 +61,16 @@ runs:
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
flavor: |
|
||||
suffix=${{ inputs.tag_suffix }},onlatest=true
|
||||
tags: |
|
||||
type=semver,pattern={{version}},prefix=v,suffix=${{ inputs.tag_suffix }}
|
||||
type=semver,pattern={{major}}.{{minor}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.0.') }},prefix=v,suffix=${{ inputs.tag_suffix }}
|
||||
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }},prefix=v,suffix=${{ inputs.tag_suffix }}
|
||||
type=ref,event=branch,prefix=${{ format('refs/heads/{0}', github.event.repository.default_branch) != github.ref && 'branch-' || '' }},suffix=${{ inputs.tag_suffix }}
|
||||
type=ref,event=pr,suffix=${{ inputs.tag_suffix }}
|
||||
type=sha,format=short,suffix=${{ inputs.tag_suffix }}
|
||||
type=raw,value=latest${{ inputs.tag_suffix }},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
type=semver,pattern={{version}},prefix=v
|
||||
type=semver,pattern={{major}}.{{minor}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.0.') }},prefix=v
|
||||
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }},prefix=v
|
||||
type=ref,event=branch,prefix=${{ format('refs/heads/{0}', github.event.repository.default_branch) != github.ref && 'branch-' || '' }},
|
||||
type=ref,event=pr
|
||||
type=sha,format=short
|
||||
type=raw,value=latest${{ inputs.tag_suffix }},enable=${{ startsWith(github.ref, 'refs/tags/v') }},priority=1100
|
||||
images: ${{ inputs.images }}
|
||||
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509
|
||||
env:
|
||||
@@ -81,6 +83,7 @@ runs:
|
||||
env:
|
||||
IMAGES: ${{ inputs.images }}
|
||||
run: |
|
||||
set -o xtrace
|
||||
IFS=$'\n'
|
||||
IMAGES_LIST=($IMAGES)
|
||||
ANNOTATIONS_LIST=($DOCKER_METADATA_OUTPUT_ANNOTATIONS)
|
||||
@@ -98,6 +101,7 @@ runs:
|
||||
env:
|
||||
IMAGES: ${{ inputs.images }}
|
||||
run: |
|
||||
set -o xtrace
|
||||
IMAGES_LIST=($IMAGES)
|
||||
for REPO in "${IMAGES_LIST[@]}"; do
|
||||
docker buildx imagetools inspect $REPO:${{ steps.meta.outputs.version }}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
name: detect-runner-os
|
||||
description: |
|
||||
Detect the actual OS name and version of the runner.
|
||||
Provides separate outputs for name, version, and a combined slug.
|
||||
|
||||
outputs:
|
||||
name:
|
||||
description: 'OS name (e.g. Ubuntu, Debian)'
|
||||
value: ${{ steps.detect.outputs.name }}
|
||||
version:
|
||||
description: 'OS version (e.g. 22.04, 11)'
|
||||
value: ${{ steps.detect.outputs.version }}
|
||||
slug:
|
||||
description: 'Combined OS slug (e.g. Ubuntu-22.04)'
|
||||
value: ${{ steps.detect.outputs.slug }}
|
||||
node_major:
|
||||
description: 'Major version of Node.js if available (e.g. 22)'
|
||||
value: ${{ steps.detect.outputs.node_major }}
|
||||
node_version:
|
||||
description: 'Full Node.js version if available (e.g. 22.19.0)'
|
||||
value: ${{ steps.detect.outputs.node_version }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Detect runner OS
|
||||
id: detect
|
||||
shell: bash
|
||||
run: |
|
||||
# Detect OS version (try lsb_release first, fall back to /etc/os-release)
|
||||
OS_VERSION=$(lsb_release -rs 2>/dev/null || grep VERSION_ID /etc/os-release | cut -d'"' -f2)
|
||||
|
||||
# Detect OS name and capitalise (try lsb_release first, fall back to /etc/os-release)
|
||||
OS_NAME=$(lsb_release -is 2>/dev/null || grep "^ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"' | sed 's/\b\(.\)/\u\1/g')
|
||||
|
||||
# Create combined slug
|
||||
OS_SLUG="${OS_NAME}-${OS_VERSION}"
|
||||
|
||||
# Detect Node.js version if available
|
||||
if command -v node >/dev/null 2>&1; then
|
||||
NODE_VERSION=$(node --version | sed 's/v//')
|
||||
NODE_MAJOR=$(echo $NODE_VERSION | cut -d. -f1)
|
||||
echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "node_major=${NODE_MAJOR}" >> $GITHUB_OUTPUT
|
||||
echo "🔍 Detected Node.js: v${NODE_VERSION}"
|
||||
else
|
||||
echo "node_version=" >> $GITHUB_OUTPUT
|
||||
echo "node_major=" >> $GITHUB_OUTPUT
|
||||
echo "🔍 Node.js not found"
|
||||
fi
|
||||
|
||||
# Set OS outputs
|
||||
echo "name=${OS_NAME}" >> $GITHUB_OUTPUT
|
||||
echo "version=${OS_VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "slug=${OS_SLUG}" >> $GITHUB_OUTPUT
|
||||
|
||||
# Log detection results
|
||||
echo "🔍 Detected Runner OS: ${OS_NAME} ${OS_VERSION}"
|
||||
@@ -121,7 +121,7 @@ runs:
|
||||
.cargo/git/checkouts
|
||||
.cargo/registry
|
||||
.cargo/registry/src
|
||||
key: rust-registry-image-${{hashFiles('**/Cargo.lock') }}
|
||||
key: continuwuity-rust-registry-image-${{hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target
|
||||
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
||||
@@ -130,7 +130,7 @@ runs:
|
||||
with:
|
||||
path: |
|
||||
cargo-target${{ env.CPU_SUFFIX }}-${{ inputs.slug }}-${{ inputs.profile }}
|
||||
key: cargo-target${{ env.CPU_SUFFIX }}-${{ inputs.slug }}-${{ inputs.profile }}-${{hashFiles('**/Cargo.lock') }}-${{steps.rust-toolchain.outputs.rustc_version}}
|
||||
key: continuwuity-cargo-target${{ env.CPU_SUFFIX }}-${{ inputs.slug }}-${{ inputs.profile }}-${{hashFiles('**/Cargo.lock') }}-${{steps.rust-toolchain.outputs.rustc_version}}
|
||||
|
||||
- name: Cache apt cache
|
||||
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
||||
@@ -139,7 +139,7 @@ runs:
|
||||
with:
|
||||
path: |
|
||||
var-cache-apt-${{ inputs.slug }}
|
||||
key: var-cache-apt-${{ inputs.slug }}
|
||||
key: continuwuity-var-cache-apt-${{ inputs.slug }}
|
||||
|
||||
- name: Cache apt lib
|
||||
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
||||
@@ -148,7 +148,7 @@ runs:
|
||||
with:
|
||||
path: |
|
||||
var-lib-apt-${{ inputs.slug }}
|
||||
key: var-lib-apt-${{ inputs.slug }}
|
||||
key: continuwuity-var-lib-apt-${{ inputs.slug }}
|
||||
|
||||
- name: inject cache into docker
|
||||
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
||||
|
||||
@@ -40,7 +40,7 @@ runs:
|
||||
!~/.rustup/tmp
|
||||
!~/.rustup/downloads
|
||||
# Requires repo to be cloned if toolchain is not specified
|
||||
key: ${{ runner.os }}-rustup-${{ inputs.toolchain || hashFiles('**/rust-toolchain.toml') }}
|
||||
key: continuwuity-${{ runner.os }}-rustup-${{ inputs.toolchain || hashFiles('**/rust-toolchain.toml') }}
|
||||
- name: Install Rust toolchain
|
||||
if: steps.rustup-version.outputs.version == ''
|
||||
shell: bash
|
||||
|
||||
@@ -29,7 +29,7 @@ runs:
|
||||
steps:
|
||||
- name: Detect runner OS
|
||||
id: runner-os
|
||||
uses: ./.forgejo/actions/detect-runner-os
|
||||
uses: https://git.tomfos.tr/actions/detect-versions@v1
|
||||
|
||||
- name: Configure cross-compilation architecture
|
||||
if: inputs.dpkg-arch != ''
|
||||
@@ -69,7 +69,7 @@ runs:
|
||||
/usr/lib/x86_64-linux-gnu/libclang*.so*
|
||||
/etc/apt/sources.list.d/archive_uri-*
|
||||
/etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||
key: llvm-${{ steps.runner-os.outputs.slug }}-v${{ inputs.llvm-version }}-v3-${{ hashFiles('**/Cargo.lock', 'rust-toolchain.toml') }}
|
||||
key: continuwuity-llvm-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}-v${{ inputs.llvm-version }}-${{ hashFiles('**/Cargo.lock', 'rust-toolchain.toml') }}
|
||||
|
||||
- name: End LLVM cache group
|
||||
shell: bash
|
||||
|
||||
@@ -39,7 +39,7 @@ runs:
|
||||
steps:
|
||||
- name: Detect runner OS
|
||||
id: runner-os
|
||||
uses: ./.forgejo/actions/detect-runner-os
|
||||
uses: https://git.tomfos.tr/actions/detect-versions@v1
|
||||
|
||||
- name: Configure Cargo environment
|
||||
shell: bash
|
||||
@@ -73,9 +73,9 @@ runs:
|
||||
.cargo/git/db
|
||||
# Registry cache saved per workflow, restored from any workflow's cache
|
||||
# Each workflow maintains its own registry that accumulates its needed crates
|
||||
key: cargo-registry-${{ steps.runner-os.outputs.slug }}-${{ github.workflow }}
|
||||
key: continuwuity-cargo-registry-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}-${{ github.workflow }}
|
||||
restore-keys: |
|
||||
cargo-registry-${{ steps.runner-os.outputs.slug }}-
|
||||
continuwuity-cargo-registry-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}-
|
||||
|
||||
- name: Cache toolchain binaries
|
||||
id: toolchain-cache
|
||||
@@ -86,29 +86,42 @@ runs:
|
||||
.rustup/toolchains
|
||||
.rustup/update-hashes
|
||||
# Shared toolchain cache across all Rust versions
|
||||
key: toolchain-${{ steps.runner-os.outputs.slug }}
|
||||
key: continuwuity-toolchain-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}
|
||||
|
||||
|
||||
- name: Setup sccache
|
||||
uses: https://git.tomfos.tr/tom/sccache-action@v1
|
||||
|
||||
- name: Cache build artifacts
|
||||
id: build-cache
|
||||
- name: Cache dependencies
|
||||
id: deps-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
target/**/deps
|
||||
!target/**/deps/*.rlib
|
||||
target/**/build
|
||||
target/**/.fingerprint
|
||||
target/**/incremental
|
||||
target/**/deps
|
||||
target/**/*.d
|
||||
target/**/.cargo-lock
|
||||
target/**/CACHEDIR.TAG
|
||||
target/**/.rustc_info.json
|
||||
/timelord/
|
||||
# Build artifacts - cache per code change, restore from deps when code changes
|
||||
# Dependencies cache - based on Cargo.lock, survives source code changes
|
||||
key: >-
|
||||
build-${{ steps.runner-os.outputs.slug }}-${{ inputs.rust-version }}${{ inputs.cache-key-suffix && format('-{0}', inputs.cache-key-suffix) || '' }}-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}-${{ hashFiles('**/*.rs', '**/Cargo.toml') }}
|
||||
continuwuity-deps-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}-${{ inputs.rust-version }}${{ inputs.cache-key-suffix && format('-{0}', inputs.cache-key-suffix) || '' }}-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
build-${{ steps.runner-os.outputs.slug }}-${{ inputs.rust-version }}${{ inputs.cache-key-suffix && format('-{0}', inputs.cache-key-suffix) || '' }}-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}-
|
||||
continuwuity-deps-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}-${{ inputs.rust-version }}${{ inputs.cache-key-suffix && format('-{0}', inputs.cache-key-suffix) || '' }}-
|
||||
|
||||
- name: Cache incremental compilation
|
||||
id: incremental-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
target/**/incremental
|
||||
# Incremental cache - based on source code changes
|
||||
key: >-
|
||||
continuwuity-incremental-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}-${{ inputs.rust-version }}${{ inputs.cache-key-suffix && format('-{0}', inputs.cache-key-suffix) || '' }}-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}-${{ hashFiles('**/*.rs', '**/Cargo.toml') }}
|
||||
restore-keys: |
|
||||
continuwuity-incremental-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}-${{ inputs.rust-version }}${{ inputs.cache-key-suffix && format('-{0}', inputs.cache-key-suffix) || '' }}-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}-
|
||||
continuwuity-incremental-${{ steps.runner-os.outputs.slug }}-${{ steps.runner-os.outputs.arch }}-${{ inputs.rust-version }}${{ inputs.cache-key-suffix && format('-{0}', inputs.cache-key-suffix) || '' }}-
|
||||
|
||||
- name: End cache restore group
|
||||
shell: bash
|
||||
|
||||
@@ -36,7 +36,7 @@ runs:
|
||||
path: |
|
||||
/usr/share/rust/.cargo/bin
|
||||
~/.cargo/bin
|
||||
key: timelord-binaries-v3
|
||||
key: continuwuity-timelord-binaries
|
||||
|
||||
- name: Check if binaries need installation
|
||||
shell: bash
|
||||
@@ -82,7 +82,7 @@ runs:
|
||||
path: |
|
||||
/usr/share/rust/.cargo/bin
|
||||
~/.cargo/bin
|
||||
key: timelord-binaries-v3
|
||||
key: continuwuity-timelord-binaries
|
||||
|
||||
|
||||
- name: Restore timelord cache with fallbacks
|
||||
@@ -92,7 +92,7 @@ runs:
|
||||
path: ${{ env.TIMELORD_CACHE_PATH }}
|
||||
key: ${{ env.TIMELORD_KEY }}
|
||||
restore-keys: |
|
||||
timelord-v1-${{ github.repository }}-
|
||||
continuwuity-timelord-${{ github.repository }}-
|
||||
|
||||
- name: Initialize timestamps on complete cache miss
|
||||
if: steps.timelord-restore.outputs.cache-hit != 'true'
|
||||
|
||||
@@ -40,6 +40,12 @@ creds:
|
||||
- registry: registry.gitlab.com
|
||||
user: "{{env \"GITLAB_USERNAME\"}}"
|
||||
pass: "{{env \"GITLAB_TOKEN\"}}"
|
||||
- registry: git.nexy7574.co.uk
|
||||
user: "{{env \"N7574_GIT_USERNAME\"}}"
|
||||
pass: "{{env \"N7574_GIT_TOKEN\"}}"
|
||||
- registry: ghcr.io
|
||||
user: "{{env \"GH_PACKAGES_USER\"}}"
|
||||
pass: "{{env \"GH_PACKAGES_TOKEN\"}}"
|
||||
|
||||
# Global defaults
|
||||
defaults:
|
||||
@@ -53,3 +59,11 @@ sync:
|
||||
target: registry.gitlab.com/continuwuity/continuwuity
|
||||
type: repository
|
||||
<<: *tags-main
|
||||
- source: *source
|
||||
target: git.nexy7574.co.uk/mirrored/continuwuity
|
||||
type: repository
|
||||
<<: *tags-releases
|
||||
- source: *source
|
||||
target: ghcr.io/continuwuity/continuwuity
|
||||
type: repository
|
||||
<<: *tags-main
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
name: Build / Debian DEB
|
||||
|
||||
concurrency:
|
||||
group: "build-debian-${{ forge.ref }}"
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '30 0 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
container: ["ubuntu-latest", "ubuntu-previous", "debian-latest", "debian-oldstable"]
|
||||
container:
|
||||
image: "ghcr.io/tcpipuk/act-runner:${{ matrix.container }}"
|
||||
|
||||
steps:
|
||||
- name: Get Debian version
|
||||
id: debian-version
|
||||
run: |
|
||||
VERSION=$(cat /etc/debian_version)
|
||||
DISTRIBUTION=$(lsb_release -sc 2>/dev/null)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "distribution=$DISTRIBUTION" >> $GITHUB_OUTPUT
|
||||
echo "Debian distribution: $DISTRIBUTION ($VERSION)"
|
||||
|
||||
- name: Checkout repository with full history
|
||||
uses: https://code.forgejo.org/actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache Cargo registry
|
||||
uses: https://code.forgejo.org/actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: cargo-debian-${{ steps.debian-version.outputs.distribution }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
cargo-debian-${{ steps.debian-version.outputs.distribution }}-
|
||||
|
||||
- name: Setup sccache
|
||||
uses: https://git.tomfos.tr/tom/sccache-action@v1
|
||||
|
||||
- name: Configure sccache environment
|
||||
run: |
|
||||
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
|
||||
echo "CMAKE_C_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
|
||||
echo "CMAKE_CXX_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
|
||||
echo "SCCACHE_CACHE_SIZE=10G" >> $GITHUB_ENV
|
||||
# Aggressive GC since cache restores don't increment counter
|
||||
echo "CARGO_INCREMENTAL_GC_TRIGGER=5" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup Rust nightly
|
||||
uses: ./.forgejo/actions/setup-rust
|
||||
with:
|
||||
rust-version: nightly
|
||||
github-token: ${{ secrets.GH_PUBLIC_RO }}
|
||||
|
||||
- name: Get package version and component
|
||||
id: package-meta
|
||||
run: |
|
||||
BASE_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r ".packages[] | select(.name == \"conduwuit\").version" | sed 's/[^a-zA-Z0-9.+]/~/g')
|
||||
# VERSION is the package version, COMPONENT is used in
|
||||
# apt's repository config like a git repo branch
|
||||
if [[ "${{ forge.ref }}" == "refs/tags/"* ]]; then
|
||||
# Use the "stable" component for tagged releases
|
||||
COMPONENT="stable"
|
||||
VERSION=$BASE_VERSION
|
||||
else
|
||||
# Use the "dev" component for development builds
|
||||
SHA=$(echo "${{ forge.sha }}" | cut -c1-7)
|
||||
DATE=$(date +%Y%m%d)
|
||||
if [ "${{ forge.ref_name }}" = "main" ]; then
|
||||
COMPONENT="dev"
|
||||
else
|
||||
# Use the sanitized ref name as the component for feature branches
|
||||
COMPONENT="dev-$(echo '${{ forge.ref_name }}' | sed 's/[^a-zA-Z0-9.+]/-/g' | tr '[:upper:]' '[:lower:]' | cut -c1-30)"
|
||||
fi
|
||||
CLEAN_COMPONENT=$(echo $COMPONENT | sed 's/[^a-zA-Z0-9.+]/~/g')
|
||||
VERSION="$BASE_VERSION~git$DATE.$SHA-$CLEAN_COMPONENT"
|
||||
fi
|
||||
echo "component=$COMPONENT" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Component: $COMPONENT"
|
||||
echo "Version: $VERSION"
|
||||
|
||||
- name: Install cargo-deb
|
||||
run: |
|
||||
if command -v cargo-deb &> /dev/null; then
|
||||
echo "cargo-deb already available"
|
||||
else
|
||||
echo "Installing cargo-deb"
|
||||
cargo-binstall -y --no-symlinks cargo-deb
|
||||
fi
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
apt-get update -y
|
||||
# Build dependencies for rocksdb
|
||||
apt-get install -y clang liburing-dev
|
||||
|
||||
- name: Run cargo-deb
|
||||
id: cargo-deb
|
||||
run: |
|
||||
DEB_PATH=$(cargo deb --deb-version ${{ steps.package-meta.outputs.version }})
|
||||
echo "path=$DEB_PATH" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Test deb installation
|
||||
run: |
|
||||
echo "Installing: ${{ steps.cargo-deb.outputs.path }}"
|
||||
|
||||
apt-get install -y ${{ steps.cargo-deb.outputs.path }}
|
||||
|
||||
dpkg -s continuwuity
|
||||
|
||||
[ -f /usr/bin/conduwuit ] && echo "✅ Binary installed successfully"
|
||||
[ -f /usr/lib/systemd/system/conduwuit.service ] && echo "✅ Systemd service installed"
|
||||
[ -f /etc/conduwuit/conduwuit.toml ] && echo "✅ Config file installed"
|
||||
|
||||
- name: Upload deb artifact
|
||||
uses: https://code.forgejo.org/actions/upload-artifact@v3
|
||||
with:
|
||||
name: continuwuity-${{ steps.debian-version.outputs.distribution }}
|
||||
path: ${{ steps.cargo-deb.outputs.path }}
|
||||
|
||||
- name: Publish to Forgejo package registry
|
||||
if: ${{ forge.event_name == 'push' || forge.event_name == 'workflow_dispatch' || forge.event_name == 'schedule' }}
|
||||
run: |
|
||||
OWNER="continuwuation"
|
||||
DISTRIBUTION=${{ steps.debian-version.outputs.distribution }}
|
||||
COMPONENT=${{ steps.package-meta.outputs.component }}
|
||||
DEB=${{ steps.cargo-deb.outputs.path }}
|
||||
|
||||
echo "Publishing: $DEB in component $COMPONENT for distribution $DISTRIBUTION"
|
||||
|
||||
curl --fail-with-body \
|
||||
-X PUT \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
--upload-file "$DEB" \
|
||||
"${{ forge.server_url }}/api/packages/$OWNER/debian/pool/$DISTRIBUTION/$COMPONENT/upload"
|
||||
@@ -0,0 +1,389 @@
|
||||
name: Build / Fedora RPM
|
||||
|
||||
concurrency:
|
||||
group: "build-fedora-${{ github.ref }}"
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
# paths:
|
||||
# - 'pkg/fedora/**'
|
||||
# - 'src/**'
|
||||
# - 'Cargo.toml'
|
||||
# - 'Cargo.lock'
|
||||
# - '.forgejo/workflows/build-fedora.yml'
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '30 0 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: fedora-latest
|
||||
steps:
|
||||
- name: Detect Fedora version
|
||||
id: fedora
|
||||
run: |
|
||||
VERSION=$(rpm -E %fedora)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Fedora version: $VERSION"
|
||||
|
||||
- name: Checkout repository with full history
|
||||
uses: https://code.forgejo.org/actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
- name: Cache DNF packages
|
||||
uses: https://code.forgejo.org/actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/var/cache/dnf
|
||||
/var/cache/yum
|
||||
key: dnf-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('pkg/fedora/continuwuity.spec.rpkg') }}-v1
|
||||
restore-keys: |
|
||||
dnf-fedora${{ steps.fedora.outputs.version }}-
|
||||
|
||||
- name: Cache Cargo registry
|
||||
uses: https://code.forgejo.org/actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: cargo-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
cargo-fedora${{ steps.fedora.outputs.version }}-
|
||||
|
||||
- name: Cache Rust build dependencies
|
||||
uses: https://code.forgejo.org/actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/rpmbuild/BUILD/*/target/release/deps
|
||||
~/rpmbuild/BUILD/*/target/release/build
|
||||
~/rpmbuild/BUILD/*/target/release/.fingerprint
|
||||
~/rpmbuild/BUILD/*/target/release/incremental
|
||||
key: rust-deps-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
rust-deps-fedora${{ steps.fedora.outputs.version }}-
|
||||
|
||||
- name: Setup sccache
|
||||
uses: https://git.tomfos.tr/tom/sccache-action@v1
|
||||
|
||||
- name: Configure sccache environment
|
||||
run: |
|
||||
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
|
||||
echo "CMAKE_C_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
|
||||
echo "CMAKE_CXX_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
|
||||
echo "SCCACHE_CACHE_SIZE=10G" >> $GITHUB_ENV
|
||||
# Aggressive GC since cache restores don't increment counter
|
||||
echo "CARGO_INCREMENTAL_GC_TRIGGER=5" >> $GITHUB_ENV
|
||||
|
||||
- name: Install base RPM tools
|
||||
run: |
|
||||
dnf install -y --setopt=keepcache=1 \
|
||||
fedora-packager \
|
||||
python3-pip \
|
||||
rpm-sign \
|
||||
rpkg \
|
||||
wget
|
||||
|
||||
- name: Setup build environment and build SRPM
|
||||
run: |
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
git config --global user.email "ci@continuwuity.org"
|
||||
git config --global user.name "Continuwuity"
|
||||
|
||||
rpmdev-setuptree
|
||||
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
|
||||
# Determine release suffix and version based on ref type and branch
|
||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||
# Tags get clean version numbers for stable releases
|
||||
RELEASE_SUFFIX=""
|
||||
TAG_NAME="${{ github.ref_name }}"
|
||||
# Extract version from tag (remove v prefix if present)
|
||||
TAG_VERSION=$(echo "$TAG_NAME" | sed 's/^v//')
|
||||
|
||||
# Create spec file with tag version
|
||||
sed -e "s/^Version:.*$/Version: $TAG_VERSION/" \
|
||||
-e "s/^Release:.*$/Release: 1%{?dist}/" \
|
||||
pkg/fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
||||
elif [ "${{ github.ref_name }}" = "main" ]; then
|
||||
# Main branch gets .dev suffix
|
||||
RELEASE_SUFFIX=".dev"
|
||||
|
||||
# Replace the Release line to include our suffix
|
||||
sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \
|
||||
pkg/fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
||||
else
|
||||
# Other branches get sanitized branch name as suffix
|
||||
SAFE_BRANCH=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/_/g' | cut -c1-20)
|
||||
RELEASE_SUFFIX=".${SAFE_BRANCH}"
|
||||
|
||||
# Replace the Release line to include our suffix
|
||||
sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \
|
||||
pkg/fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
||||
fi
|
||||
|
||||
rpkg srpm --outdir "$HOME/rpmbuild/SRPMS"
|
||||
|
||||
ls -la $HOME/rpmbuild/SRPMS/
|
||||
|
||||
|
||||
- name: Install build dependencies from SRPM
|
||||
run: |
|
||||
SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1)
|
||||
|
||||
if [ -z "$SRPM" ]; then
|
||||
echo "Error: No SRPM file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Installing build dependencies from: $(basename $SRPM)"
|
||||
dnf builddep -y "$SRPM"
|
||||
|
||||
- name: Build RPM from SRPM
|
||||
run: |
|
||||
SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1)
|
||||
|
||||
if [ -z "$SRPM" ]; then
|
||||
echo "Error: No SRPM file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building from SRPM: $SRPM"
|
||||
|
||||
rpmbuild --rebuild "$SRPM" \
|
||||
--define "_topdir $HOME/rpmbuild" \
|
||||
--define "_sourcedir $GITHUB_WORKSPACE" \
|
||||
--nocheck # Skip %check section to avoid test dependencies
|
||||
|
||||
|
||||
- name: Test RPM installation
|
||||
run: |
|
||||
# Find the main binary RPM (exclude debug and source RPMs)
|
||||
RPM=$(find "$HOME/rpmbuild/RPMS" -name "continuwuity-*.rpm" \
|
||||
! -name "*debuginfo*" \
|
||||
! -name "*debugsource*" \
|
||||
! -name "*.src.rpm" | head -1)
|
||||
|
||||
if [ -z "$RPM" ]; then
|
||||
echo "Error: No binary RPM file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Testing installation of: $RPM"
|
||||
|
||||
# Dry run first
|
||||
rpm -qpi "$RPM"
|
||||
echo ""
|
||||
rpm -qpl "$RPM"
|
||||
|
||||
# Actually install it
|
||||
dnf install -y "$RPM"
|
||||
|
||||
# Verify installation
|
||||
rpm -qa | grep continuwuity
|
||||
|
||||
# Check that the binary exists
|
||||
[ -f /usr/bin/conduwuit ] && echo "✅ Binary installed successfully"
|
||||
[ -f /usr/lib/systemd/system/conduwuit.service ] && echo "✅ Systemd service installed"
|
||||
[ -f /etc/conduwuit/conduwuit.toml ] && echo "✅ Config file installed"
|
||||
|
||||
- name: List built packages
|
||||
run: |
|
||||
echo "Binary RPMs:"
|
||||
find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec ls -la {} \;
|
||||
|
||||
echo ""
|
||||
echo "Source RPMs:"
|
||||
find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec ls -la {} \;
|
||||
|
||||
- name: Collect artifacts
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
|
||||
find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
|
||||
find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
|
||||
|
||||
cd artifacts
|
||||
echo "Build Information:" > BUILD_INFO.txt
|
||||
echo "==================" >> BUILD_INFO.txt
|
||||
echo "Git commit: ${{ github.sha }}" >> BUILD_INFO.txt
|
||||
echo "Git branch: ${{ github.ref_name }}" >> BUILD_INFO.txt
|
||||
echo "Build date: $(date -u +%Y-%m-%d_%H:%M:%S_UTC)" >> BUILD_INFO.txt
|
||||
echo "" >> BUILD_INFO.txt
|
||||
echo "Package contents:" >> BUILD_INFO.txt
|
||||
echo "-----------------" >> BUILD_INFO.txt
|
||||
for rpm in *.rpm; do
|
||||
echo "" >> BUILD_INFO.txt
|
||||
echo "File: $rpm" >> BUILD_INFO.txt
|
||||
rpm -qpi "$rpm" 2>/dev/null | grep -E "^(Name|Version|Release|Architecture|Size)" >> BUILD_INFO.txt
|
||||
done
|
||||
|
||||
ls -la
|
||||
|
||||
- name: Upload binary RPM artifact
|
||||
run: |
|
||||
# Find the main binary RPM (exclude debug and source RPMs)
|
||||
BIN_RPM=$(find artifacts -name "continuwuity-*.rpm" \
|
||||
! -name "*debuginfo*" \
|
||||
! -name "*debugsource*" \
|
||||
! -name "*.src.rpm" \
|
||||
-type f)
|
||||
|
||||
mkdir -p upload-bin
|
||||
cp $BIN_RPM upload-bin/
|
||||
|
||||
- name: Upload binary RPM
|
||||
uses: https://code.forgejo.org/actions/upload-artifact@v3
|
||||
with:
|
||||
name: continuwuity
|
||||
path: upload-bin/
|
||||
|
||||
- name: Upload debug RPM artifact
|
||||
uses: https://code.forgejo.org/actions/upload-artifact@v3
|
||||
with:
|
||||
name: continuwuity-debug
|
||||
path: artifacts/*debuginfo*.rpm
|
||||
|
||||
- name: Publish to RPM Package Registry
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }}
|
||||
run: |
|
||||
# Find the main binary RPM (exclude debug and source RPMs)
|
||||
RPM=$(find artifacts -name "continuwuity-*.rpm" \
|
||||
! -name "*debuginfo*" \
|
||||
! -name "*debugsource*" \
|
||||
! -name "*.src.rpm" \
|
||||
-type f | head -1)
|
||||
|
||||
if [ -z "$RPM" ]; then
|
||||
echo "No binary RPM found to publish"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RPM_BASENAME=$(basename "$RPM")
|
||||
echo "Publishing: $RPM_BASENAME"
|
||||
|
||||
# Determine the group based on ref type and branch
|
||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||
GROUP="stable"
|
||||
# For tags, extract the tag name for version info
|
||||
TAG_NAME="${{ github.ref_name }}"
|
||||
elif [ "${{ github.ref_name }}" = "main" ]; then
|
||||
GROUP="dev"
|
||||
else
|
||||
# Use sanitized branch name as group for feature branches
|
||||
GROUP=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]' | cut -c1-30)
|
||||
fi
|
||||
|
||||
PACKAGE_INFO=$(rpm -qpi "$RPM" 2>/dev/null)
|
||||
PACKAGE_NAME=$(echo "$PACKAGE_INFO" | grep "^Name" | awk '{print $3}')
|
||||
PACKAGE_VERSION=$(echo "$PACKAGE_INFO" | grep "^Version" | awk '{print $3}')
|
||||
PACKAGE_RELEASE=$(echo "$PACKAGE_INFO" | grep "^Release" | awk '{print $3}')
|
||||
PACKAGE_ARCH=$(echo "$PACKAGE_INFO" | grep "^Architecture" | awk '{print $2}')
|
||||
|
||||
# Full version includes release
|
||||
FULL_VERSION="${PACKAGE_VERSION}-${PACKAGE_RELEASE}"
|
||||
|
||||
# Forgejo's RPM registry cannot overwrite existing packages, so we must delete first
|
||||
# 404 is OK if package doesn't exist yet
|
||||
echo "Removing any existing package: $PACKAGE_NAME-$FULL_VERSION.$PACKAGE_ARCH"
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/package/$PACKAGE_NAME/$FULL_VERSION/$PACKAGE_ARCH")
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
||||
echo "ERROR: Failed to delete package (HTTP $HTTP_CODE)"
|
||||
echo "$RESPONSE" | head -n -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl --fail-with-body \
|
||||
-X PUT \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
-H "Content-Type: application/x-rpm" \
|
||||
-T "$RPM" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/upload?sign=true"
|
||||
|
||||
echo ""
|
||||
echo "✅ Published binary RPM to: https://forgejo.ellis.link/continuwuation/-/packages/rpm/continuwuity/"
|
||||
echo "Group: $GROUP"
|
||||
|
||||
# Upload debug RPMs to separate group
|
||||
DEBUG_RPMS=$(find artifacts -name "*debuginfo*.rpm")
|
||||
if [ -n "$DEBUG_RPMS" ]; then
|
||||
echo ""
|
||||
echo "Publishing debug RPMs to group: ${GROUP}-debug"
|
||||
|
||||
for DEBUG_RPM in $DEBUG_RPMS; do
|
||||
echo "Publishing: $(basename "$DEBUG_RPM")"
|
||||
|
||||
DEBUG_INFO=$(rpm -qpi "$DEBUG_RPM" 2>/dev/null)
|
||||
DEBUG_NAME=$(echo "$DEBUG_INFO" | grep "^Name" | awk '{print $3}')
|
||||
DEBUG_VERSION=$(echo "$DEBUG_INFO" | grep "^Version" | awk '{print $3}')
|
||||
DEBUG_RELEASE=$(echo "$DEBUG_INFO" | grep "^Release" | awk '{print $3}')
|
||||
DEBUG_ARCH=$(echo "$DEBUG_INFO" | grep "^Architecture" | awk '{print $2}')
|
||||
DEBUG_FULL_VERSION="${DEBUG_VERSION}-${DEBUG_RELEASE}"
|
||||
|
||||
# Must delete existing package first (Forgejo limitation)
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-debug/package/$DEBUG_NAME/$DEBUG_FULL_VERSION/$DEBUG_ARCH")
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
||||
echo "ERROR: Failed to delete debug package (HTTP $HTTP_CODE)"
|
||||
echo "$RESPONSE" | head -n -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl --fail-with-body \
|
||||
-X PUT \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
-H "Content-Type: application/x-rpm" \
|
||||
-T "$DEBUG_RPM" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-debug/upload?sign=true"
|
||||
done
|
||||
|
||||
echo "✅ Published debug RPMs to group: ${GROUP}-debug"
|
||||
fi
|
||||
|
||||
# Also upload the SRPM to separate group
|
||||
SRPM=$(find artifacts -name "*.src.rpm" | head -1)
|
||||
if [ -n "$SRPM" ]; then
|
||||
echo ""
|
||||
echo "Publishing source RPM: $(basename "$SRPM")"
|
||||
echo "Publishing to group: ${GROUP}-src"
|
||||
|
||||
SRPM_INFO=$(rpm -qpi "$SRPM" 2>/dev/null)
|
||||
SRPM_NAME=$(echo "$SRPM_INFO" | grep "^Name" | awk '{print $3}')
|
||||
SRPM_VERSION=$(echo "$SRPM_INFO" | grep "^Version" | awk '{print $3}')
|
||||
SRPM_RELEASE=$(echo "$SRPM_INFO" | grep "^Release" | awk '{print $3}')
|
||||
SRPM_FULL_VERSION="${SRPM_VERSION}-${SRPM_RELEASE}"
|
||||
|
||||
# Must delete existing SRPM first (Forgejo limitation)
|
||||
echo "Removing any existing SRPM: $SRPM_NAME-$SRPM_FULL_VERSION.src"
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/package/$SRPM_NAME/$SRPM_FULL_VERSION/src")
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
||||
echo "ERROR: Failed to delete SRPM (HTTP $HTTP_CODE)"
|
||||
echo "$RESPONSE" | head -n -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl --fail-with-body \
|
||||
-X PUT \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
-H "Content-Type: application/x-rpm" \
|
||||
-T "$SRPM" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/upload?sign=true"
|
||||
|
||||
echo "✅ Published source RPM to group: ${GROUP}-src"
|
||||
fi
|
||||
@@ -51,11 +51,11 @@ jobs:
|
||||
|
||||
- name: Detect runner environment
|
||||
id: runner-env
|
||||
uses: ./.forgejo/actions/detect-runner-os
|
||||
uses: https://git.tomfos.tr/actions/detect-versions@v1
|
||||
|
||||
- name: Setup Node.js
|
||||
if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20'
|
||||
uses: https://github.com/actions/setup-node@v5
|
||||
uses: https://github.com/actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
@@ -63,9 +63,7 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ steps.runner-env.outputs.slug }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ steps.runner-env.outputs.slug }}-node-
|
||||
key: continuwuity-${{ steps.runner-env.outputs.slug }}-${{ steps.runner-env.outputs.arch }}-node-${{ steps.runner-env.outputs.node_version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install --save-dev wrangler@latest
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 📦 Setup Node.js
|
||||
uses: https://github.com/actions/setup-node@v5
|
||||
uses: https://github.com/actions/setup-node@v6
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
|
||||
@@ -11,7 +11,13 @@ on:
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
# Re-run when config changes
|
||||
- '.forgejo/regsync/regsync.yml'
|
||||
- '.forgejo/workflows/mirror-images.yml'
|
||||
concurrency:
|
||||
group: "mirror-images"
|
||||
cancel-in-progress: true
|
||||
@@ -24,12 +30,25 @@ jobs:
|
||||
BUILTIN_REGISTRY_PASSWORD: ${{ secrets.BUILTIN_REGISTRY_PASSWORD }}
|
||||
GITLAB_USERNAME: ${{ vars.GITLAB_USERNAME }}
|
||||
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
|
||||
N7574_GIT_USERNAME: ${{ vars.N7574_GIT_USERNAME }}
|
||||
N7574_GIT_TOKEN: ${{ secrets.N7574_GIT_TOKEN }}
|
||||
GH_PACKAGES_USER: ${{ vars.GH_PACKAGES_USER }}
|
||||
GH_PACKAGES_TOKEN: ${{ secrets.GH_PACKAGES_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# - uses: https://github.com/actions/create-github-app-token@v2
|
||||
# id: app-token
|
||||
# with:
|
||||
# app-id: ${{ vars.GH_APP_ID }}
|
||||
# private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
||||
# github-api-url: https://api.github.com
|
||||
# owner: continuwuity
|
||||
# repositories: continuwuity
|
||||
|
||||
- name: Install regctl
|
||||
uses: https://forgejo.ellis.link/continuwuation/regclient-actions/regctl-installer@main
|
||||
with:
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
name: Renovate
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/renovatebot/renovate:41.121.4@sha256:c3348a8cc65f3519ec3412d3b9787dc2ae151052220f87f533bfdded051227a9
|
||||
image: ghcr.io/renovatebot/renovate:41.146.4@sha256:bb70194b7405faf10a6f279b60caa10403a440ba37d158c5a4ef0ae7b67a0f92
|
||||
options: --tmpfs /tmp:exec
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -59,27 +59,27 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
/tmp/renovate/cache/renovate/repository
|
||||
key: repo-cache-${{ github.run_id }}
|
||||
key: renovate-repo-cache-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
repo-cache-
|
||||
renovate-repo-cache-
|
||||
|
||||
- name: Restore renovate package cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
/tmp/renovate/cache/renovate/renovate-cache-sqlite
|
||||
key: package-cache-${{ github.run_id }}
|
||||
key: renovate-package-cache-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
package-cache-
|
||||
renovate-package-cache-
|
||||
|
||||
- name: Restore renovate OSV cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
/tmp/osv
|
||||
key: osv-cache-${{ github.run_id }}
|
||||
key: renovate-osv-cache-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
osv-cache-
|
||||
renovate-osv-cache-
|
||||
|
||||
- name: Self-hosted Renovate
|
||||
run: renovate
|
||||
@@ -113,7 +113,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
/tmp/renovate/cache/renovate/repository
|
||||
key: repo-cache-${{ github.run_id }}
|
||||
key: renovate-repo-cache-${{ github.run_id }}
|
||||
|
||||
- name: Save renovate package cache
|
||||
if: always()
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
/tmp/renovate/cache/renovate/renovate-cache-sqlite
|
||||
key: package-cache-${{ github.run_id }}
|
||||
key: renovate-package-cache-${{ github.run_id }}
|
||||
|
||||
- name: Save renovate OSV cache
|
||||
if: always()
|
||||
@@ -129,4 +129,4 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
/tmp/osv
|
||||
key: osv-cache-${{ github.run_id }}
|
||||
key: renovate-osv-cache-${{ github.run_id }}
|
||||
|
||||
@@ -7,6 +7,8 @@ on:
|
||||
- "Cargo.lock"
|
||||
- "Cargo.toml"
|
||||
- "rust-toolchain.toml"
|
||||
- "nix/**/*"
|
||||
- ".forgejo/workflows/update-flake-hashes.yml"
|
||||
|
||||
jobs:
|
||||
update-flake-hashes:
|
||||
@@ -14,13 +16,13 @@ jobs:
|
||||
steps:
|
||||
- uses: https://code.forgejo.org/actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
with:
|
||||
fetch-depth: 1
|
||||
fetch-depth: 0
|
||||
fetch-tags: false
|
||||
fetch-single-branch: true
|
||||
submodules: false
|
||||
persist-credentials: false
|
||||
|
||||
- uses: https://github.com/cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
|
||||
- uses: https://github.com/cachix/install-nix-action@7ab6e7fd29da88e74b1e314a4ae9ac6b5cda3801 # v31.8.0
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
@@ -39,13 +41,22 @@ jobs:
|
||||
echo "Base: $base"
|
||||
echo "HEAD: $(git rev-parse HEAD)"
|
||||
git diff --name-only $base HEAD > changed_files.txt
|
||||
echo "files=$(cat changed_files.txt)" >> $FORGEJO_OUTPUT
|
||||
echo "detected changes in $(cat changed_files.txt)"
|
||||
# Join files with commas
|
||||
files=$(paste -sd, changed_files.txt)
|
||||
echo "files=$files" >> $FORGEJO_OUTPUT
|
||||
|
||||
- name: Debug output
|
||||
run: |
|
||||
echo "State of output"
|
||||
echo "Changed files: ${{ steps.changes.outputs.files }}"
|
||||
|
||||
- name: Get new toolchain hash
|
||||
if: contains(steps.changes.outputs.files, 'Cargo.toml') || contains(steps.changes.outputs.files, 'Cargo.lock') || contains(steps.changes.outputs.files, 'rust-toolchain.toml')
|
||||
run: |
|
||||
# Set the current sha256 to an empty hash to make `nix build` calculate a new one
|
||||
awk '/fromToolchainFile *\{/{found=1; print; next} found && /sha256 =/{sub(/sha256 = .*/, "sha256 = pkgsHost.lib.fakeSha256;"); found=0} 1' flake.nix > temp.nix && mv temp.nix flake.nix
|
||||
awk '/fromToolchainFile *\{/{found=1; print; next} found && /sha256 =/{sub(/sha256 = .*/, "sha256 = lib.fakeSha256;"); found=0} 1' nix/packages/rust.nix > temp.nix
|
||||
mv temp.nix nix/packages/rust.nix
|
||||
|
||||
# Build continuwuity and filter for the new hash
|
||||
# We do `|| true` because we want this to fail without stopping the workflow
|
||||
@@ -53,19 +64,21 @@ jobs:
|
||||
|
||||
# Place the new hash in place of the empty hash
|
||||
new_hash=$(cat new_toolchain_hash.txt)
|
||||
sed -i "s|pkgsHost.lib.fakeSha256|\"$new_hash\"|" flake.nix
|
||||
sed -i "s|lib.fakeSha256|\"$new_hash\"|" nix/packages/rust.nix
|
||||
|
||||
echo "New hash:"
|
||||
awk -F'"' '/fromToolchainFile/{found=1; next} found && /sha256 =/{print $2; found=0}' flake.nix
|
||||
awk -F'"' '/fromToolchainFile/{found=1; next} found && /sha256 =/{print $2; found=0}' nix/packages/rust.nix
|
||||
echo "Expected new hash:"
|
||||
cat new_toolchain_hash.txt
|
||||
|
||||
rm new_toolchain_hash.txt
|
||||
|
||||
- name: Get new rocksdb hash
|
||||
if: contains(steps.changes.outputs.files, '.nix') || contains(steps.changes.outputs.files, 'flake.lock')
|
||||
run: |
|
||||
# Set the current sha256 to an empty hash to make `nix build` calculate a new one
|
||||
awk '/repo = "rocksdb";/{found=1; print; next} found && /sha256 =/{sub(/sha256 = .*/, "sha256 = pkgsHost.lib.fakeSha256;"); found=0} 1' flake.nix > temp.nix && mv temp.nix flake.nix
|
||||
awk '/repo = "rocksdb";/{found=1; print; next} found && /sha256 =/{sub(/sha256 = .*/, "sha256 = lib.fakeSha256;"); found=0} 1' nix/packages/rocksdb/package.nix > temp.nix
|
||||
mv temp.nix nix/packages/rocksdb/package.nix
|
||||
|
||||
# Build continuwuity and filter for the new hash
|
||||
# We do `|| true` because we want this to fail without stopping the workflow
|
||||
@@ -73,17 +86,17 @@ jobs:
|
||||
|
||||
# Place the new hash in place of the empty hash
|
||||
new_hash=$(cat new_rocksdb_hash.txt)
|
||||
sed -i "s|pkgsHost.lib.fakeSha256|\"$new_hash\"|" flake.nix
|
||||
sed -i "s|lib.fakeSha256|\"$new_hash\"|" nix/packages/rocksdb/package.nix
|
||||
|
||||
echo "New hash:"
|
||||
awk -F'"' '/repo = "rocksdb";/{found=1; next} found && /sha256 =/{print $2; found=0}' flake.nix
|
||||
awk -F'"' '/repo = "rocksdb";/{found=1; next} found && /sha256 =/{print $2; found=0}' nix/packages/rocksdb/package.nix
|
||||
echo "Expected new hash:"
|
||||
cat new_rocksdb_hash.txt
|
||||
|
||||
rm new_rocksdb_hash.txt
|
||||
|
||||
- name: Show diff
|
||||
run: git diff flake.nix
|
||||
run: git diff flake.nix nix
|
||||
|
||||
- name: Push changes
|
||||
run: |
|
||||
|
||||
@@ -7,7 +7,7 @@ default_stages:
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
rev: v6.0.0
|
||||
hooks:
|
||||
- id: fix-byte-order-marker
|
||||
- id: check-case-conflict
|
||||
@@ -23,7 +23,7 @@ repos:
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/crate-ci/typos
|
||||
rev: v1.26.0
|
||||
rev: v1.39.0
|
||||
hooks:
|
||||
- id: typos
|
||||
- id: typos
|
||||
|
||||
Generated
+635
-1030
File diff suppressed because it is too large
Load Diff
+20
-33
@@ -21,7 +21,7 @@ license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://forgejo.ellis.link/continuwuation/continuwuity"
|
||||
rust-version = "1.86.0"
|
||||
version = "0.5.0-rc.8.1"
|
||||
version = "0.5.0-rc.8"
|
||||
|
||||
[workspace.metadata.crane]
|
||||
name = "conduwuit"
|
||||
@@ -166,8 +166,8 @@ default-features = false
|
||||
features = ["raw_value"]
|
||||
|
||||
# Used for appservice registration files
|
||||
[workspace.dependencies.serde_yml]
|
||||
version = "0.0.12"
|
||||
[workspace.dependencies.serde-saphyr]
|
||||
version = "0.0.7"
|
||||
|
||||
# Used to load forbidden room/user regex from config
|
||||
[workspace.dependencies.serde_regex]
|
||||
@@ -210,13 +210,13 @@ default-features = false
|
||||
version = "0.1.41"
|
||||
default-features = false
|
||||
[workspace.dependencies.tracing-subscriber]
|
||||
version = "0.3.19"
|
||||
version = "0.3.20"
|
||||
default-features = false
|
||||
features = ["env-filter", "std", "tracing", "tracing-log", "ansi", "fmt"]
|
||||
[workspace.dependencies.tracing-journald]
|
||||
version = "0.3.1"
|
||||
[workspace.dependencies.tracing-core]
|
||||
version = "0.1.33"
|
||||
version = "0.1.34"
|
||||
default-features = false
|
||||
|
||||
# for URL previews
|
||||
@@ -286,7 +286,7 @@ features = [
|
||||
]
|
||||
|
||||
[workspace.dependencies.hyper-util]
|
||||
version = "0.1.11"
|
||||
version = "=0.1.17"
|
||||
default-features = false
|
||||
features = [
|
||||
"server-auto",
|
||||
@@ -351,7 +351,7 @@ version = "0.1.2"
|
||||
# Used for matrix spec type definitions and helpers
|
||||
[workspace.dependencies.ruma]
|
||||
git = "https://forgejo.ellis.link/continuwuation/ruwuma"
|
||||
rev = "d18823471ab3c09e77ff03eea346d4c07e572654"
|
||||
rev = "50b2a91b2ab8f9830eea80b9911e11234e0eac66"
|
||||
features = [
|
||||
"compat",
|
||||
"rand",
|
||||
@@ -412,28 +412,27 @@ default-features = false
|
||||
|
||||
# optional opentelemetry, performance measurements, flamegraphs, etc for performance measurements and monitoring
|
||||
[workspace.dependencies.opentelemetry]
|
||||
version = "0.30.0"
|
||||
version = "0.31.0"
|
||||
|
||||
[workspace.dependencies.tracing-flame]
|
||||
version = "0.2.0"
|
||||
|
||||
[workspace.dependencies.tracing-opentelemetry]
|
||||
version = "0.31.0"
|
||||
version = "0.32.0"
|
||||
|
||||
[workspace.dependencies.opentelemetry_sdk]
|
||||
version = "0.30.0"
|
||||
version = "0.31.0"
|
||||
features = ["rt-tokio"]
|
||||
|
||||
[workspace.dependencies.opentelemetry-otlp]
|
||||
version = "0.30.0"
|
||||
version = "0.31.0"
|
||||
features = ["http", "trace", "logs", "metrics"]
|
||||
|
||||
[workspace.dependencies.opentelemetry-jaeger-propagator]
|
||||
version = "0.30.0"
|
||||
|
||||
|
||||
# optional sentry metrics for crash/panic reporting
|
||||
[workspace.dependencies.sentry]
|
||||
version = "0.42.0"
|
||||
version = "0.45.0"
|
||||
default-features = false
|
||||
features = [
|
||||
"backtrace",
|
||||
@@ -449,9 +448,9 @@ features = [
|
||||
]
|
||||
|
||||
[workspace.dependencies.sentry-tracing]
|
||||
version = "0.42.0"
|
||||
version = "0.45.0"
|
||||
[workspace.dependencies.sentry-tower]
|
||||
version = "0.42.0"
|
||||
version = "0.45.0"
|
||||
|
||||
# jemalloc usage
|
||||
[workspace.dependencies.tikv-jemalloc-sys]
|
||||
@@ -477,7 +476,7 @@ default-features = false
|
||||
features = ["use_std"]
|
||||
|
||||
[workspace.dependencies.console-subscriber]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
|
||||
[workspace.dependencies.nix]
|
||||
version = "0.30.1"
|
||||
@@ -551,9 +550,9 @@ features = ["std"]
|
||||
version = "1.0.2"
|
||||
|
||||
[workspace.dependencies.ldap3]
|
||||
version = "0.11.5"
|
||||
version = "0.12.0"
|
||||
default-features = false
|
||||
features = ["sync", "tls-rustls"]
|
||||
features = ["sync", "tls-rustls", "rustls-provider"]
|
||||
|
||||
[workspace.dependencies.resolv-conf]
|
||||
version = "0.7.5"
|
||||
@@ -564,19 +563,7 @@ version = "0.7.5"
|
||||
|
||||
# backport of [https://github.com/tokio-rs/tracing/pull/2956] to the 0.1.x branch of tracing.
|
||||
# we can switch back to upstream if #2956 is merged and backported in the upstream repo.
|
||||
# https://forgejo.ellis.link/continuwuation/tracing/commit/b348dca742af641c47bc390261f60711c2af573c
|
||||
[patch.crates-io.tracing-subscriber]
|
||||
git = "https://forgejo.ellis.link/continuwuation/tracing"
|
||||
rev = "1e64095a8051a1adf0d1faa307f9f030889ec2aa"
|
||||
[patch.crates-io.tracing]
|
||||
git = "https://forgejo.ellis.link/continuwuation/tracing"
|
||||
rev = "1e64095a8051a1adf0d1faa307f9f030889ec2aa"
|
||||
[patch.crates-io.tracing-core]
|
||||
git = "https://forgejo.ellis.link/continuwuation/tracing"
|
||||
rev = "1e64095a8051a1adf0d1faa307f9f030889ec2aa"
|
||||
[patch.crates-io.tracing-log]
|
||||
git = "https://forgejo.ellis.link/continuwuation/tracing"
|
||||
rev = "1e64095a8051a1adf0d1faa307f9f030889ec2aa"
|
||||
|
||||
|
||||
# adds a tab completion callback: https://forgejo.ellis.link/continuwuation/rustyline-async/src/branch/main/.patchy/0002-add-tab-completion-callback.patch
|
||||
# adds event for CTRL+\: https://forgejo.ellis.link/continuwuation/rustyline-async/src/branch/main/.patchy/0001-add-event-for-ctrl.patch
|
||||
@@ -600,7 +587,7 @@ rev = "9c8e51510c35077df888ee72a36b4b05637147da"
|
||||
# reverts hyperium#148 conflicting with our delicate federation resolver hooks
|
||||
[patch.crates-io.hyper-util]
|
||||
git = "https://forgejo.ellis.link/continuwuation/hyper-util"
|
||||
rev = "e4ae7628fe4fcdacef9788c4c8415317a4489941"
|
||||
rev = "5886d5292bf704c246206ad72d010d674a7b77d0"
|
||||
|
||||
#
|
||||
# Our crates
|
||||
|
||||
@@ -957,6 +957,21 @@
|
||||
#
|
||||
#rocksdb_bottommost_compression = true
|
||||
|
||||
# Compression algorithm for RocksDB's Write-Ahead-Log (WAL).
|
||||
#
|
||||
# At present, only ZSTD compression is supported by RocksDB for WAL
|
||||
# compression. Enabling this can reduce WAL size at the expense of some
|
||||
# CPU usage during writes.
|
||||
#
|
||||
# The options are:
|
||||
# - "none" = No compression
|
||||
# - "zstd" = ZSTD compression
|
||||
#
|
||||
# For more information on WAL compression, see:
|
||||
# https://github.com/facebook/rocksdb/wiki/WAL-Compression
|
||||
#
|
||||
#rocksdb_wal_compression = "zstd"
|
||||
|
||||
# Database recovery mode (for RocksDB WAL corruption).
|
||||
#
|
||||
# Use this option when the server reports corruption and refuses to start.
|
||||
@@ -1497,6 +1512,19 @@
|
||||
#
|
||||
#block_non_admin_invites = false
|
||||
|
||||
# Enable or disable making requests to MSC4284 Policy Servers.
|
||||
# It is recommended you keep this enabled unless you experience frequent
|
||||
# connectivity issues, such as in a restricted networking environment.
|
||||
#
|
||||
#enable_msc4284_policy_servers = true
|
||||
|
||||
# Enable running locally generated events through configured MSC4284
|
||||
# policy servers. You may wish to disable this if your server is
|
||||
# single-user for a slight speed benefit in some rooms, but otherwise
|
||||
# should leave it enabled.
|
||||
#
|
||||
#policy_server_check_own_events = true
|
||||
|
||||
# Allow admins to enter commands in rooms other than "#admins" (admin
|
||||
# room) by prefixing your message with "\!admin" or "\\!admin" followed up
|
||||
# a normal continuwuity admin command. The reply will be publicly visible
|
||||
|
||||
+2
-2
@@ -48,7 +48,7 @@ EOF
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.15.5
|
||||
ENV BINSTALL_VERSION=1.15.10
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
@@ -166,7 +166,7 @@ ARG RUST_PROFILE=release
|
||||
# Build the binary
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/usr/local/cargo/git/db \
|
||||
--mount=type=cache,target=/app/target,id=cargo-target-${TARGET_CPU}-${TARGETPLATFORM}-${RUST_PROFILE} \
|
||||
--mount=type=cache,target=/app/target,id=continuwuity-cargo-target-${TARGET_CPU}-${TARGETPLATFORM}-${RUST_PROFILE} \
|
||||
bash <<'EOF'
|
||||
set -o allexport
|
||||
set -o xtrace
|
||||
|
||||
@@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/etc/apk/cache apk add \
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.15.5
|
||||
ENV BINSTALL_VERSION=1.15.10
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
@@ -122,7 +122,7 @@ ARG RUST_PROFILE=release
|
||||
# Build the binary
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/usr/local/cargo/git/db \
|
||||
--mount=type=cache,target=/app/target,id=cargo-target-${TARGET_CPU}-${TARGETPLATFORM}-musl-${RUST_PROFILE} \
|
||||
--mount=type=cache,target=/app/target,id=continuwuity-cargo-target-${TARGET_CPU}-${TARGETPLATFORM}-musl-${RUST_PROFILE} \
|
||||
bash <<'EOF'
|
||||
set -o allexport
|
||||
set -o xtrace
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
- [Kubernetes](deploying/kubernetes.md)
|
||||
- [Arch Linux](deploying/arch-linux.md)
|
||||
- [Debian](deploying/debian.md)
|
||||
- [Fedora](deploying/fedora.md)
|
||||
- [FreeBSD](deploying/freebsd.md)
|
||||
- [TURN](turn.md)
|
||||
- [Appservices](appservices.md)
|
||||
|
||||
+18
-3
@@ -1078,7 +1078,10 @@ Respecting homeservers put this file here for listing administration, moderation
|
||||
|
||||
* `delete` — - Deletes a single media file from our database and on the filesystem via a single MXC URL or event ID (not redacted)
|
||||
* `delete-list` — - Deletes a codeblock list of MXC URLs from our database and on the filesystem. This will always ignore errors
|
||||
* `delete-past-remote-media` — - Deletes all remote (and optionally local) media created before or after [duration] time using filesystem metadata first created at date, or fallback to last modified date. This will always ignore errors by default
|
||||
* `delete-past-remote-media` — Deletes all remote (and optionally local) media created before/after
|
||||
[duration] ago, using filesystem metadata first created at date, or
|
||||
fallback to last modified date. This will always ignore errors by
|
||||
default.
|
||||
* `delete-all-from-user` — - Deletes all the local media from a local user on our server. This will always ignore errors by default
|
||||
* `delete-all-from-server` — - Deletes all remote media from the specified remote server. This will always ignore errors by default
|
||||
* `get-file-info` —
|
||||
@@ -1110,13 +1113,25 @@ Respecting homeservers put this file here for listing administration, moderation
|
||||
|
||||
## `admin media delete-past-remote-media`
|
||||
|
||||
- Deletes all remote (and optionally local) media created before or after [duration] time using filesystem metadata first created at date, or fallback to last modified date. This will always ignore errors by default
|
||||
Deletes all remote (and optionally local) media created before/after
|
||||
[duration] ago, using filesystem metadata first created at date, or
|
||||
fallback to last modified date. This will always ignore errors by
|
||||
default.
|
||||
|
||||
* Examples:
|
||||
* Delete all remote media older than a year:
|
||||
|
||||
`!admin media delete-past-remote-media -b 1y`
|
||||
|
||||
* Delete all remote and local media from 3 days ago, up until now:
|
||||
|
||||
`!admin media delete-past-remote-media -a 3d --yes-i-want-to-delete-local-media`
|
||||
|
||||
**Usage:** `admin media delete-past-remote-media [OPTIONS] <DURATION>`
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<DURATION>` — - The relative time (e.g. 30s, 5m, 7d) within which to search
|
||||
* `<DURATION>` — - The relative time (e.g. 30s, 5m, 7d) from now within which to search
|
||||
|
||||
###### **Options:**
|
||||
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
# RPM Installation Guide
|
||||
|
||||
Continuwuity is available as RPM packages for Fedora, RHEL, and compatible distributions.
|
||||
|
||||
The RPM packaging files are maintained in the `fedora/` directory:
|
||||
- `continuwuity.spec.rpkg` - RPM spec file using rpkg macros for building from git
|
||||
- `continuwuity.service` - Systemd service file for the server
|
||||
- `RPM-GPG-KEY-continuwuity.asc` - GPG public key for verifying signed packages
|
||||
|
||||
RPM packages built by CI are signed with our GPG key (Ed25519, ID: `5E0FF73F411AAFCA`).
|
||||
|
||||
```bash
|
||||
# Import the signing key
|
||||
sudo rpm --import https://forgejo.ellis.link/continuwuation/continuwuity/raw/branch/main/fedora/RPM-GPG-KEY-continuwuity.asc
|
||||
|
||||
# Verify a downloaded package
|
||||
rpm --checksig continuwuity-*.rpm
|
||||
```
|
||||
|
||||
## Installation methods
|
||||
|
||||
**Stable releases** (recommended)
|
||||
|
||||
```bash
|
||||
# Add the repository and install
|
||||
sudo dnf config-manager addrepo --from-repofile=https://forgejo.ellis.link/api/packages/continuwuation/rpm/stable/continuwuation.repo
|
||||
sudo dnf install continuwuity
|
||||
```
|
||||
|
||||
**Development builds** from main branch
|
||||
|
||||
```bash
|
||||
# Add the dev repository and install
|
||||
sudo dnf config-manager addrepo --from-repofile=https://forgejo.ellis.link/api/packages/continuwuation/rpm/dev/continuwuation.repo
|
||||
sudo dnf install continuwuity
|
||||
```
|
||||
|
||||
**Feature branch builds** (example: `tom/new-feature`)
|
||||
|
||||
```bash
|
||||
# Branch names are sanitized (slashes become hyphens, lowercase only)
|
||||
sudo dnf config-manager addrepo --from-repofile=https://forgejo.ellis.link/api/packages/continuwuation/rpm/tom-new-feature/continuwuation.repo
|
||||
sudo dnf install continuwuity
|
||||
```
|
||||
|
||||
**Direct installation** without adding repository
|
||||
|
||||
```bash
|
||||
# Latest stable release
|
||||
sudo dnf install https://forgejo.ellis.link/api/packages/continuwuation/rpm/stable/continuwuity
|
||||
|
||||
# Latest development build
|
||||
sudo dnf install https://forgejo.ellis.link/api/packages/continuwuation/rpm/dev/continuwuity
|
||||
|
||||
# Specific feature branch
|
||||
sudo dnf install https://forgejo.ellis.link/api/packages/continuwuation/rpm/branch-name/continuwuity
|
||||
```
|
||||
|
||||
**Manual repository configuration** (alternative method)
|
||||
|
||||
```bash
|
||||
cat << 'EOF' | sudo tee /etc/yum.repos.d/continuwuity.repo
|
||||
[continuwuity]
|
||||
name=Continuwuity - Matrix homeserver
|
||||
baseurl=https://forgejo.ellis.link/api/packages/continuwuation/rpm/stable
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
gpgkey=https://forgejo.ellis.link/continuwuation/continuwuity/raw/branch/main/fedora/RPM-GPG-KEY-continuwuity.asc
|
||||
EOF
|
||||
|
||||
sudo dnf install continuwuity
|
||||
```
|
||||
|
||||
## Package management
|
||||
|
||||
**Automatic updates** with DNF Automatic
|
||||
|
||||
```bash
|
||||
# Install and configure
|
||||
sudo dnf install dnf-automatic
|
||||
sudo nano /etc/dnf/automatic.conf # Set: apply_updates = yes
|
||||
sudo systemctl enable --now dnf-automatic.timer
|
||||
```
|
||||
|
||||
**Manual updates**
|
||||
|
||||
```bash
|
||||
# Check for updates
|
||||
sudo dnf check-update continuwuity
|
||||
|
||||
# Update to latest version
|
||||
sudo dnf update continuwuity
|
||||
```
|
||||
|
||||
**Switching channels** (stable/dev/feature branches)
|
||||
|
||||
```bash
|
||||
# List enabled repositories
|
||||
dnf repolist | grep continuwuation
|
||||
|
||||
# Disable current repository
|
||||
sudo dnf config-manager --set-disabled continuwuation-stable # or -dev, or branch name
|
||||
|
||||
# Enable desired repository
|
||||
sudo dnf config-manager --set-enabled continuwuation-dev # or -stable, or branch name
|
||||
|
||||
# Update to the new channel's version
|
||||
sudo dnf update continuwuity
|
||||
```
|
||||
|
||||
**Verifying installation**
|
||||
|
||||
```bash
|
||||
# Check installed version
|
||||
rpm -q continuwuity
|
||||
|
||||
# View package information
|
||||
rpm -qi continuwuity
|
||||
|
||||
# List installed files
|
||||
rpm -ql continuwuity
|
||||
|
||||
# Verify package integrity
|
||||
rpm -V continuwuity
|
||||
```
|
||||
|
||||
## Service management and removal
|
||||
|
||||
**Systemd service commands**
|
||||
|
||||
```bash
|
||||
# Start the service
|
||||
sudo systemctl start conduwuit
|
||||
|
||||
# Enable on boot
|
||||
sudo systemctl enable conduwuit
|
||||
|
||||
# Check status
|
||||
sudo systemctl status conduwuit
|
||||
|
||||
# View logs
|
||||
sudo journalctl -u conduwuit -f
|
||||
```
|
||||
|
||||
**Uninstallation**
|
||||
|
||||
```bash
|
||||
# Stop and disable the service
|
||||
sudo systemctl stop conduwuit
|
||||
sudo systemctl disable conduwuit
|
||||
|
||||
# Remove the package
|
||||
sudo dnf remove continuwuity
|
||||
|
||||
# Remove the repository (optional)
|
||||
sudo rm /etc/yum.repos.d/continuwuation-*.repo
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**GPG key errors**: Temporarily disable GPG checking
|
||||
|
||||
```bash
|
||||
sudo dnf --nogpgcheck install continuwuity
|
||||
```
|
||||
|
||||
**Repository metadata issues**: Clear and rebuild cache
|
||||
|
||||
```bash
|
||||
sudo dnf clean all
|
||||
sudo dnf makecache
|
||||
```
|
||||
|
||||
**Finding specific versions**
|
||||
|
||||
```bash
|
||||
# List all available versions
|
||||
dnf --showduplicates list continuwuity
|
||||
|
||||
# Install a specific version
|
||||
sudo dnf install continuwuity-<version>
|
||||
```
|
||||
|
||||
## Building locally
|
||||
|
||||
Build the RPM locally using rpkg:
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
sudo dnf install rpkg rpm-build cargo-rpm-macros systemd-rpm-macros
|
||||
|
||||
# Clone the repository
|
||||
git clone https://forgejo.ellis.link/continuwuation/continuwuity.git
|
||||
cd continuwuity
|
||||
|
||||
# Build SRPM
|
||||
rpkg srpm
|
||||
|
||||
# Build RPM
|
||||
rpmbuild --rebuild *.src.rpm
|
||||
```
|
||||
@@ -241,7 +241,7 @@ lock_b.with_lock(|data_b| {
|
||||
### Code Comments
|
||||
|
||||
- Reference related documentation or parts of the specification
|
||||
- When a task has multiple ways of being acheved, explain your reasoning for your decision
|
||||
- When a task has multiple ways of being achieved, explain your reasoning for your decision
|
||||
- Update comments when code changes
|
||||
|
||||
```rs
|
||||
|
||||
Vendored
-4
@@ -8,10 +8,6 @@
|
||||
{
|
||||
"id": 3,
|
||||
"message": "_taps microphone_ The Continuwuity 0.5.0-rc.7 release is now available, and it's better than ever! **177 commits**, **35 pull requests**, **11 contributors,** and a lot of new stuff!\n\nFor highlights, we've got:\n\n* 🕵️ Full Policy Server support to fight spam!\n* 🚀 Smarter room & space upgrades.\n* 🚫 User suspension tools for better moderation.\n* 🤖 reCaptcha support for safer open registration.\n* 🔍 Ability to disable read receipts & typing indicators.\n* ⚡ Sweeping performance improvements!\n\nGet the [full changelog and downloads on our Forgejo](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.0-rc.7) - and make sure you're in the [Announcements room](https://matrix.to/#/!releases:continuwuity.org/$hN9z6L2_dTAlPxFLAoXVfo_g8DyYXu4cpvWsSrWhmB0) to get stuff like this sooner."
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"message": "It's a bird! It's a plane! No, it's 0.5.0-rc.8.1!\n\nThis is a minor bugfix update to the rc8 which backports some important fixes from the latest main branch. If you still haven't updated to rc8, you should skip to main. Otherwise, you should upgrade to this bugfix release as soon as possible.\n\nBugfixes backported to this version:\n\n- Resolved several issues with state resolution v2.1 (room version 12)\n- Fixed issues with the `restricted` and `knock_restricted` join rules that would sometimes incorrectly disallow a valid join\n- Fixed the automatic support contact listing being a no-op\n- Fixed upgrading pre-v12 rooms to v12 rooms\n- Fixed policy servers sending the incorrect JSON objects (resulted in false positives)\n- Fixed debug build panic during MSC4133 migration\n\nIt is recommended, if you can and are comfortable with doing so, following updates to the main branch - we're in the run up to the full 0.5.0 release, and more and more bugfixes and new features are being pushed constantly. Please don't forget to join [#announcements:continuwuity.org](https://matrix.to/#/#announcements:continuwuity.org) to receive this news faster and be alerted to other important updates!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Generated
+52
-399
@@ -1,94 +1,28 @@
|
||||
{
|
||||
"nodes": {
|
||||
"attic": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-parts": "flake-parts",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"advisory-db": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1757683818,
|
||||
"narHash": "sha256-q7q0pWT+wu5AUU1Qlbwq8Mqb+AzHKhaMCVUq/HNZfo8=",
|
||||
"owner": "zhaofengli",
|
||||
"repo": "attic",
|
||||
"rev": "7c5d79ad62cda340cb8c80c99b921b7b7ffacf69",
|
||||
"lastModified": 1761112158,
|
||||
"narHash": "sha256-RIXu/7eyKpQHjsPuAUODO81I4ni8f+WYSb7K4mTG6+0=",
|
||||
"owner": "rustsec",
|
||||
"repo": "advisory-db",
|
||||
"rev": "58f3aaec0e1776f4a900737be8cd7cb00972210d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "zhaofengli",
|
||||
"ref": "main",
|
||||
"repo": "attic",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"cachix": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"flake-compat": "flake-compat_2",
|
||||
"git-hooks": "git-hooks",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1756385612,
|
||||
"narHash": "sha256-+NU5MMhuPHHRyvZZWNFG7zt+leRSPsJu1MwhOUzkPUk=",
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"rev": "dc24688cd67518c3711d511fa369c0f5a131063a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "master",
|
||||
"repo": "cachix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"cachix_2": {
|
||||
"inputs": {
|
||||
"devenv": [
|
||||
"cachix",
|
||||
"devenv"
|
||||
],
|
||||
"flake-compat": [
|
||||
"cachix",
|
||||
"devenv"
|
||||
],
|
||||
"git-hooks": [
|
||||
"cachix",
|
||||
"devenv",
|
||||
"git-hooks"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748883665,
|
||||
"narHash": "sha256-R0W7uAg+BLoHjMRMQ8+oiSbTq8nkGz5RDpQ+ZfxxP3A=",
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"rev": "f707778d902af4d62d8dd92c269f8e70de09acbe",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "latest",
|
||||
"repo": "cachix",
|
||||
"owner": "rustsec",
|
||||
"repo": "advisory-db",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1751562746,
|
||||
"narHash": "sha256-smpugNIkmDeicNz301Ll1bD7nFOty97T79m4GUMUczA=",
|
||||
"lastModified": 1760924934,
|
||||
"narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "aed2020fd3dc26e1e857d4107a5a67a33ab6c1fd",
|
||||
"rev": "c6b4d5308293d0d04fcfeee92705017537cad02f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -97,53 +31,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"crane_2": {
|
||||
"locked": {
|
||||
"lastModified": 1757183466,
|
||||
"narHash": "sha256-kTdCCMuRE+/HNHES5JYsbRHmgtr+l9mOtf5dpcMppVc=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "d599ae4847e7f87603e7082d73ca673aa93c916d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"ref": "master",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"cachix": "cachix_2",
|
||||
"flake-compat": [
|
||||
"cachix",
|
||||
"flake-compat"
|
||||
],
|
||||
"git-hooks": [
|
||||
"cachix",
|
||||
"git-hooks"
|
||||
],
|
||||
"nix": "nix",
|
||||
"nixpkgs": [
|
||||
"cachix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1754404745,
|
||||
"narHash": "sha256-BdbW/iTImczgcuATgQIa9sPGuYIBxVq2xqcvICsa2AQ=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "6563b21105168f90394dfaf58284b078af2d7275",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -152,53 +39,20 @@
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758004879,
|
||||
"narHash": "sha256-kV7tQzcNbmo58wg2uE2MQ/etaTx+PxBMHeNrLP8vOgk=",
|
||||
"lastModified": 1761115517,
|
||||
"narHash": "sha256-Fev/ag/c3Fp3JBwHfup3lpA5FlNXfkoshnQ7dssBgJ0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "07e5ce53dd020e6b337fdddc934561bee0698fa2",
|
||||
"rev": "320433651636186ea32b387cff05d6bbfa30cea7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "main",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747046372,
|
||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747046372,
|
||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_3": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747046372,
|
||||
@@ -217,17 +71,14 @@
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"attic",
|
||||
"nixpkgs"
|
||||
]
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1751413152,
|
||||
"narHash": "sha256-Tyw1RjYEsp5scoigs1384gIg6e0GoBVjms4aXFfRssQ=",
|
||||
"lastModified": 1760948891,
|
||||
"narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "77826244401ea9de6e3bac47c2db46005e1f30b5",
|
||||
"rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -236,214 +87,13 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733312601,
|
||||
"narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"ref": "main",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"git-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"cachix",
|
||||
"flake-compat"
|
||||
],
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"cachix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750779888,
|
||||
"narHash": "sha256-wibppH3g/E2lxU43ZQHC5yA/7kIKLGxVEnsnVK1BtRg=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "16ec914f6fb6f599ce988427d9d94efddf25fe6d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"cachix",
|
||||
"git-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"cachix",
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"flake-parts": "flake-parts_2",
|
||||
"git-hooks-nix": [
|
||||
"cachix",
|
||||
"devenv",
|
||||
"git-hooks"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-23-11": [
|
||||
"cachix",
|
||||
"devenv"
|
||||
],
|
||||
"nixpkgs-regression": [
|
||||
"cachix",
|
||||
"devenv"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752773918,
|
||||
"narHash": "sha256-dOi/M6yNeuJlj88exI+7k154z+hAhFcuB8tZktiW7rg=",
|
||||
"owner": "cachix",
|
||||
"repo": "nix",
|
||||
"rev": "031c3cf42d2e9391eee373507d8c12e0f9606779",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "devenv-2.30",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-filter": {
|
||||
"locked": {
|
||||
"lastModified": 1757882181,
|
||||
"narHash": "sha256-+cCxYIh2UNalTz364p+QYmWHs0P+6wDhiWR4jDIKQIU=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-filter",
|
||||
"rev": "59c44d1909c72441144b93cf0f054be7fe764de5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"ref": "main",
|
||||
"repo": "nix-filter",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"attic",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737420293,
|
||||
"narHash": "sha256-F1G5ifvqTpJq7fdkT34e/Jy9VCyzd5XfJ9TO8fHhJWE=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "f4158fa080ef4503c8f4c820967d946c2af31ec9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1751949589,
|
||||
"narHash": "sha256-mgFxAPLWw0Kq+C8P3dRrZrOYEQXOtKuYVlo9xvPntt8=",
|
||||
"lastModified": 1760878510,
|
||||
"narHash": "sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9b008d60392981ad674e04016d25619281550a9d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1751741127,
|
||||
"narHash": "sha256-t75Shs76NgxjZSgvvZZ9qOmz5zuBE8buUaYD28BMTxg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "29e290002bfff26af1db6f64d070698019460302",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1754214453,
|
||||
"narHash": "sha256-Q/I2xJn/j1wpkGhWkQnm20nShYnG7TI99foDBpXm1SY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5b09dc45f24cf32316283e62aec81ffee3c3e376",
|
||||
"rev": "5e2a59a5b1a82f89f2c7e598302a9cacebb72a67",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -453,42 +103,40 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1758029226,
|
||||
"narHash": "sha256-TjqVmbpoCqWywY9xIZLTf6ANFvDCXdctCjoYuYPYdMI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "08b8f92ac6354983f5382124fef6006cade4a1c1",
|
||||
"lastModified": 1754788789,
|
||||
"narHash": "sha256-x2rJ+Ovzq0sCMpgfgGaaqgBSwY+LST+WbZ6TytnT9Rk=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "a73b9c743612e4244d865a2fdee11865283c04e6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"attic": "attic",
|
||||
"cachix": "cachix",
|
||||
"crane": "crane_2",
|
||||
"advisory-db": "advisory-db",
|
||||
"crane": "crane",
|
||||
"fenix": "fenix",
|
||||
"flake-compat": "flake-compat_3",
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-filter": "nix-filter",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1757362324,
|
||||
"narHash": "sha256-/PAhxheUq4WBrW5i/JHzcCqK5fGWwLKdH6/Lu1tyS18=",
|
||||
"lastModified": 1761077270,
|
||||
"narHash": "sha256-O1uTuvI/rUlubJ8AXKyzh1WSWV3qCZX0huTFUvWLN4E=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "9edc9cbe5d8e832b5864e09854fa94861697d2fd",
|
||||
"rev": "39990a923c8bca38f5bd29dc4c96e20ee7808d5d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -498,18 +146,23 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"lastModified": 1760945191,
|
||||
"narHash": "sha256-ZRVs8UqikBa4Ki3X4KCnMBtBW0ux1DaT35tgsnB1jM4=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "f56b1934f5f8fcab8deb5d38d42fd692632b47c2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,351 +1,46 @@
|
||||
{
|
||||
description = "A nix flake for the continuwuity project";
|
||||
|
||||
inputs = {
|
||||
attic.url = "github:zhaofengli/attic?ref=main";
|
||||
cachix.url = "github:cachix/cachix?ref=master";
|
||||
crane = {
|
||||
url = "github:ipetkov/crane?ref=master";
|
||||
};
|
||||
# basics
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
# for rust via nix
|
||||
crane.url = "github:ipetkov/crane";
|
||||
fenix = {
|
||||
url = "github:nix-community/fenix?ref=main";
|
||||
url = "github:nix-community/fenix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
# for vuln checks
|
||||
advisory-db = {
|
||||
url = "github:rustsec/advisory-db";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
treefmt-nix = {
|
||||
url = "github:numtide/treefmt-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
# for default.nix
|
||||
flake-compat = {
|
||||
url = "github:edolstra/flake-compat?ref=master";
|
||||
flake = false;
|
||||
};
|
||||
flake-utils.url = "github:numtide/flake-utils?ref=main";
|
||||
nix-filter.url = "github:numtide/nix-filter?ref=main";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixpkgs-unstable";
|
||||
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs:
|
||||
inputs.flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgsHost = import inputs.nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
|
||||
fnx = inputs.fenix.packages.${system};
|
||||
# The Rust toolchain to use
|
||||
toolchain = fnx.combine [
|
||||
(fnx.fromToolchainFile {
|
||||
file = ./rust-toolchain.toml;
|
||||
|
||||
# See also `rust-toolchain.toml`
|
||||
sha256 = "sha256-+9FmLhAOezBZCOziO0Qct1NOrfpjNsXxc/8I0c7BdKE=";
|
||||
})
|
||||
fnx.complete.rustfmt
|
||||
];
|
||||
|
||||
mkScope =
|
||||
pkgs:
|
||||
pkgs.lib.makeScope pkgs.newScope (self: {
|
||||
inherit pkgs inputs;
|
||||
craneLib = (inputs.crane.mkLib pkgs).overrideToolchain (_: toolchain);
|
||||
main = self.callPackage ./pkg/nix/pkgs/main { };
|
||||
liburing = pkgs.liburing.overrideAttrs {
|
||||
# Tests weren't building
|
||||
outputs = [
|
||||
"out"
|
||||
"dev"
|
||||
"man"
|
||||
];
|
||||
buildFlags = [ "library" ];
|
||||
};
|
||||
rocksdb =
|
||||
(pkgs.rocksdb_9_10.override {
|
||||
# Override the liburing input for the build with our own so
|
||||
# we have it built with the library flag
|
||||
inherit (self) liburing;
|
||||
}).overrideAttrs
|
||||
(old: {
|
||||
src = pkgsHost.fetchFromGitea {
|
||||
domain = "forgejo.ellis.link";
|
||||
owner = "continuwuation";
|
||||
repo = "rocksdb";
|
||||
rev = "10.4.fb";
|
||||
sha256 = "sha256-/Hvy1yTH/0D5aa7bc+/uqFugCQq4InTdwlRw88vA5IY=";
|
||||
};
|
||||
version = "v10.4.fb";
|
||||
cmakeFlags =
|
||||
pkgs.lib.subtractLists [
|
||||
# No real reason to have snappy or zlib, no one uses this
|
||||
"-DWITH_SNAPPY=1"
|
||||
"-DZLIB=1"
|
||||
"-DWITH_ZLIB=1"
|
||||
# We don't need to use ldb or sst_dump (core_tools)
|
||||
"-DWITH_CORE_TOOLS=1"
|
||||
# We don't need to build rocksdb tests
|
||||
"-DWITH_TESTS=1"
|
||||
# We use rust-rocksdb via C interface and don't need C++ RTTI
|
||||
"-DUSE_RTTI=1"
|
||||
# This doesn't exist in RocksDB, and USE_SSE is deprecated for
|
||||
# PORTABLE=$(march)
|
||||
"-DFORCE_SSE42=1"
|
||||
# PORTABLE will get set in main/default.nix
|
||||
"-DPORTABLE=1"
|
||||
] old.cmakeFlags
|
||||
++ [
|
||||
# No real reason to have snappy, no one uses this
|
||||
"-DWITH_SNAPPY=0"
|
||||
"-DZLIB=0"
|
||||
"-DWITH_ZLIB=0"
|
||||
# We don't need to use ldb or sst_dump (core_tools)
|
||||
"-DWITH_CORE_TOOLS=0"
|
||||
# We don't need trace tools
|
||||
"-DWITH_TRACE_TOOLS=0"
|
||||
# We don't need to build rocksdb tests
|
||||
"-DWITH_TESTS=0"
|
||||
# We use rust-rocksdb via C interface and don't need C++ RTTI
|
||||
"-DUSE_RTTI=0"
|
||||
];
|
||||
|
||||
# outputs has "tools" which we don't need or use
|
||||
outputs = [ "out" ];
|
||||
|
||||
# preInstall hooks has stuff for messing with ldb/sst_dump which we don't need or use
|
||||
preInstall = "";
|
||||
|
||||
# We have this already at https://forgejo.ellis.link/continuwuation/rocksdb/commit/a935c0273e1ba44eacf88ce3685a9b9831486155
|
||||
# Unsetting this so we don't have to revert it and make this nix exclusive
|
||||
patches = [ ];
|
||||
|
||||
postPatch = ''
|
||||
# Fix gcc-13 build failures due to missing <cstdint> and
|
||||
# <system_error> includes, fixed upstream since 8.x
|
||||
sed -e '1i #include <cstdint>' -i db/compaction/compaction_iteration_stats.h
|
||||
sed -e '1i #include <cstdint>' -i table/block_based/data_block_hash_index.h
|
||||
sed -e '1i #include <cstdint>' -i util/string_util.h
|
||||
sed -e '1i #include <cstdint>' -i include/rocksdb/utilities/checkpoint.h
|
||||
'';
|
||||
});
|
||||
});
|
||||
|
||||
scopeHost = mkScope pkgsHost;
|
||||
mkCrossScope =
|
||||
crossSystem:
|
||||
let
|
||||
pkgsCrossStatic =
|
||||
(import inputs.nixpkgs {
|
||||
inherit system;
|
||||
crossSystem = {
|
||||
config = crossSystem;
|
||||
};
|
||||
}).pkgsStatic;
|
||||
in
|
||||
mkScope pkgsCrossStatic;
|
||||
|
||||
in
|
||||
{
|
||||
packages =
|
||||
{
|
||||
default = scopeHost.main.override {
|
||||
disable_features = [
|
||||
# Don't include experimental features
|
||||
"experimental"
|
||||
# jemalloc profiling/stats features are expensive and shouldn't
|
||||
# be expected on non-debug builds.
|
||||
"jemalloc_prof"
|
||||
"jemalloc_stats"
|
||||
# This is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
};
|
||||
default-debug = scopeHost.main.override {
|
||||
profile = "dev";
|
||||
# Debug build users expect full logs
|
||||
disable_release_max_log_level = true;
|
||||
disable_features = [
|
||||
# Don't include experimental features
|
||||
"experimental"
|
||||
# This is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
};
|
||||
# Just a test profile used for things like CI and complement
|
||||
default-test = scopeHost.main.override {
|
||||
profile = "test";
|
||||
disable_release_max_log_level = true;
|
||||
disable_features = [
|
||||
# Don't include experimental features
|
||||
"experimental"
|
||||
# this is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
};
|
||||
all-features = scopeHost.main.override {
|
||||
all_features = true;
|
||||
disable_features = [
|
||||
# Don't include experimental features
|
||||
"experimental"
|
||||
# jemalloc profiling/stats features are expensive and shouldn't
|
||||
# be expected on non-debug builds.
|
||||
"jemalloc_prof"
|
||||
"jemalloc_stats"
|
||||
# This is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
};
|
||||
all-features-debug = scopeHost.main.override {
|
||||
profile = "dev";
|
||||
all_features = true;
|
||||
# Debug build users expect full logs
|
||||
disable_release_max_log_level = true;
|
||||
disable_features = [
|
||||
# Don't include experimental features
|
||||
"experimental"
|
||||
# This is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
};
|
||||
hmalloc = scopeHost.main.override { features = [ "hardened_malloc" ]; };
|
||||
}
|
||||
// builtins.listToAttrs (
|
||||
builtins.concatLists (
|
||||
builtins.map
|
||||
(
|
||||
crossSystem:
|
||||
let
|
||||
binaryName = "static-${crossSystem}";
|
||||
scopeCrossStatic = mkCrossScope crossSystem;
|
||||
in
|
||||
[
|
||||
# An output for a statically-linked binary
|
||||
{
|
||||
name = binaryName;
|
||||
value = scopeCrossStatic.main;
|
||||
}
|
||||
|
||||
# An output for a statically-linked binary with x86_64 haswell
|
||||
# target optimisations
|
||||
{
|
||||
name = "${binaryName}-x86_64-haswell-optimised";
|
||||
value = scopeCrossStatic.main.override {
|
||||
x86_64_haswell_target_optimised =
|
||||
if (crossSystem == "x86_64-linux-gnu" || crossSystem == "x86_64-linux-musl") then true else false;
|
||||
};
|
||||
}
|
||||
|
||||
# An output for a statically-linked unstripped debug ("dev") binary
|
||||
{
|
||||
name = "${binaryName}-debug";
|
||||
value = scopeCrossStatic.main.override {
|
||||
profile = "dev";
|
||||
# debug build users expect full logs
|
||||
disable_release_max_log_level = true;
|
||||
};
|
||||
}
|
||||
|
||||
# An output for a statically-linked unstripped debug binary with the
|
||||
# "test" profile (for CI usage only)
|
||||
{
|
||||
name = "${binaryName}-test";
|
||||
value = scopeCrossStatic.main.override {
|
||||
profile = "test";
|
||||
disable_release_max_log_level = true;
|
||||
disable_features = [
|
||||
# dont include experimental features
|
||||
"experimental"
|
||||
# this is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
# An output for a statically-linked binary with `--all-features`
|
||||
{
|
||||
name = "${binaryName}-all-features";
|
||||
value = scopeCrossStatic.main.override {
|
||||
all_features = true;
|
||||
disable_features = [
|
||||
# dont include experimental features
|
||||
"experimental"
|
||||
# jemalloc profiling/stats features are expensive and shouldn't
|
||||
# be expected on non-debug builds.
|
||||
"jemalloc_prof"
|
||||
"jemalloc_stats"
|
||||
# this is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
# An output for a statically-linked binary with `--all-features` and with x86_64 haswell
|
||||
# target optimisations
|
||||
{
|
||||
name = "${binaryName}-all-features-x86_64-haswell-optimised";
|
||||
value = scopeCrossStatic.main.override {
|
||||
all_features = true;
|
||||
disable_features = [
|
||||
# dont include experimental features
|
||||
"experimental"
|
||||
# jemalloc profiling/stats features are expensive and shouldn't
|
||||
# be expected on non-debug builds.
|
||||
"jemalloc_prof"
|
||||
"jemalloc_stats"
|
||||
# this is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
x86_64_haswell_target_optimised =
|
||||
if (crossSystem == "x86_64-linux-gnu" || crossSystem == "x86_64-linux-musl") then true else false;
|
||||
};
|
||||
}
|
||||
|
||||
# An output for a statically-linked unstripped debug ("dev") binary with `--all-features`
|
||||
{
|
||||
name = "${binaryName}-all-features-debug";
|
||||
value = scopeCrossStatic.main.override {
|
||||
profile = "dev";
|
||||
all_features = true;
|
||||
# debug build users expect full logs
|
||||
disable_release_max_log_level = true;
|
||||
disable_features = [
|
||||
# dont include experimental features
|
||||
"experimental"
|
||||
# this is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
# An output for a statically-linked binary with hardened_malloc
|
||||
{
|
||||
name = "${binaryName}-hmalloc";
|
||||
value = scopeCrossStatic.main.override {
|
||||
features = [ "hardened_malloc" ];
|
||||
};
|
||||
}
|
||||
]
|
||||
)
|
||||
[
|
||||
#"x86_64-apple-darwin"
|
||||
#"aarch64-apple-darwin"
|
||||
"x86_64-linux-gnu"
|
||||
"x86_64-linux-musl"
|
||||
"aarch64-linux-musl"
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [ ./nix ];
|
||||
systems = [
|
||||
# good support
|
||||
"x86_64-linux"
|
||||
# support untested but theoretically there
|
||||
"aarch64-linux"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
self',
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
uwulib = inputs.self.uwulib.init pkgs;
|
||||
|
||||
rocksdbAllFeatures = self'.packages.rocksdb.override {
|
||||
enableJemalloc = true;
|
||||
enableLiburing = true;
|
||||
};
|
||||
|
||||
commonAttrs = (uwulib.build.commonAttrs { }) // {
|
||||
buildInputs = [
|
||||
pkgs.liburing
|
||||
pkgs.rust-jemalloc-sys-unprefixed
|
||||
rocksdbAllFeatures
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
pkgs.pkg-config
|
||||
# bindgen needs the build platform's libclang. Apparently due to "splicing
|
||||
# weirdness", pkgs.rustPlatform.bindgenHook on its own doesn't quite do the
|
||||
# right thing here.
|
||||
pkgs.rustPlatform.bindgenHook
|
||||
];
|
||||
env = {
|
||||
LIBCLANG_PATH = lib.makeLibraryPath [ pkgs.llvmPackages.libclang.lib ];
|
||||
LD_LIBRARY_PATH = lib.makeLibraryPath [
|
||||
pkgs.liburing
|
||||
pkgs.rust-jemalloc-sys-unprefixed
|
||||
rocksdbAllFeatures
|
||||
];
|
||||
}
|
||||
// uwulib.environment.buildPackageEnv
|
||||
// {
|
||||
ROCKSDB_INCLUDE_DIR = "${rocksdbAllFeatures}/include";
|
||||
ROCKSDB_LIB_DIR = "${rocksdbAllFeatures}/lib";
|
||||
};
|
||||
};
|
||||
cargoArtifacts = self'.packages.continuwuity-all-features-deps;
|
||||
in
|
||||
{
|
||||
# taken from
|
||||
#
|
||||
# https://crane.dev/examples/quick-start.html
|
||||
checks = {
|
||||
continuwuity-all-features-build = self'.packages.continuwuity-all-features-bin;
|
||||
|
||||
continuwuity-all-features-clippy = uwulib.build.craneLibForChecks.cargoClippy (
|
||||
commonAttrs
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
cargoClippyExtraArgs = "-- --deny warnings";
|
||||
}
|
||||
);
|
||||
|
||||
continuwuity-all-features-docs = uwulib.build.craneLibForChecks.cargoDoc (
|
||||
commonAttrs
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
# This can be commented out or tweaked as necessary, e.g. set to
|
||||
# `--deny rustdoc::broken-intra-doc-links` to only enforce that lint
|
||||
env.RUSTDOCFLAGS = "--deny warnings";
|
||||
}
|
||||
);
|
||||
|
||||
# Check formatting
|
||||
continuwuity-all-features-fmt = uwulib.build.craneLibForChecks.cargoFmt {
|
||||
src = uwulib.build.src;
|
||||
};
|
||||
|
||||
continuwuity-all-features-toml-fmt = uwulib.build.craneLibForChecks.taploFmt {
|
||||
src = pkgs.lib.sources.sourceFilesBySuffices uwulib.build.src [ ".toml" ];
|
||||
# taplo arguments can be further customized below as needed
|
||||
taploExtraArgs = "--config ${inputs.self}/taplo.toml";
|
||||
};
|
||||
|
||||
# Audit dependencies
|
||||
continuwuity-all-features-audit = uwulib.build.craneLibForChecks.cargoAudit {
|
||||
inherit (inputs) advisory-db;
|
||||
src = uwulib.build.src;
|
||||
};
|
||||
|
||||
# Audit licenses
|
||||
continuwuity-all-features-deny = uwulib.build.craneLibForChecks.cargoDeny {
|
||||
src = uwulib.build.src;
|
||||
};
|
||||
|
||||
# Run tests with cargo-nextest
|
||||
# Consider setting `doCheck = false` on `continuwuity-all-features` if you do not want
|
||||
# the tests to run twice
|
||||
continuwuity-all-features-nextest = uwulib.build.craneLibForChecks.cargoNextest (
|
||||
commonAttrs
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
partitions = 1;
|
||||
partitionType = "count";
|
||||
cargoNextestPartitionsExtraArgs = "--no-tests=pass";
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
imports = [
|
||||
./checks
|
||||
./packages
|
||||
./shells
|
||||
./tests
|
||||
|
||||
./hydra.nix
|
||||
./fmt.nix
|
||||
];
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
# load the flake module from upstream
|
||||
imports = [ inputs.treefmt-nix.flakeModule ];
|
||||
|
||||
perSystem =
|
||||
{ self', lib, ... }:
|
||||
{
|
||||
treefmt = {
|
||||
# repo root as project root
|
||||
projectRoot = inputs.self;
|
||||
|
||||
# the formatters
|
||||
programs = {
|
||||
nixfmt.enable = true;
|
||||
typos = {
|
||||
enable = true;
|
||||
configFile = "${inputs.self}/.typos.toml";
|
||||
};
|
||||
taplo = {
|
||||
enable = true;
|
||||
settings = lib.importTOML "${inputs.self}/taplo.toml";
|
||||
};
|
||||
};
|
||||
|
||||
settings.formatter.rustfmt = {
|
||||
command = "${lib.getExe' self'.packages.dev-toolchain "rustfmt"}";
|
||||
includes = [ "**/*.rs" ];
|
||||
options = [
|
||||
"--unstable-features"
|
||||
"--edition=2024"
|
||||
"--config-path=${inputs.self}/rustfmt.toml"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{ inputs, ... }:
|
||||
let
|
||||
lib = inputs.nixpkgs.lib;
|
||||
in
|
||||
{
|
||||
flake.hydraJobs.packages = builtins.mapAttrs (
|
||||
_name: lib.hydraJob
|
||||
) inputs.self.packages.x86_64-linux;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
self',
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
uwulib = inputs.self.uwulib.init pkgs;
|
||||
in
|
||||
{
|
||||
packages =
|
||||
lib.pipe
|
||||
[
|
||||
# this is the default variant
|
||||
{
|
||||
variantName = "default";
|
||||
commonAttrsArgs.profile = "release";
|
||||
rocksdb = self'.packages.rocksdb;
|
||||
features = { };
|
||||
}
|
||||
# this is the variant with all features enabled (liburing + jemalloc)
|
||||
{
|
||||
variantName = "all-features";
|
||||
commonAttrsArgs.profile = "release";
|
||||
rocksdb = self'.packages.rocksdb.override {
|
||||
enableJemalloc = true;
|
||||
enableLiburing = true;
|
||||
};
|
||||
features = {
|
||||
enabledFeatures = "all";
|
||||
disabledFeatures = uwulib.features.defaultDisabledFeatures ++ [ "bindgen-static" ];
|
||||
};
|
||||
}
|
||||
]
|
||||
[
|
||||
(builtins.map (cfg: rec {
|
||||
deps = {
|
||||
name = "continuwuity-${cfg.variantName}-deps";
|
||||
value = uwulib.build.buildDeps {
|
||||
features = uwulib.features.calcFeatures cfg.features;
|
||||
inherit (cfg) commonAttrsArgs rocksdb;
|
||||
};
|
||||
};
|
||||
bin = {
|
||||
name = "continuwuity-${cfg.variantName}-bin";
|
||||
value = uwulib.build.buildPackage {
|
||||
deps = self'.packages.${deps.name};
|
||||
features = uwulib.features.calcFeatures cfg.features;
|
||||
inherit (cfg) commonAttrsArgs rocksdb;
|
||||
};
|
||||
};
|
||||
}))
|
||||
(builtins.concatMap builtins.attrValues)
|
||||
builtins.listToAttrs
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
imports = [
|
||||
./continuwuity
|
||||
./rocksdb
|
||||
./rust.nix
|
||||
./uwulib
|
||||
];
|
||||
|
||||
perSystem =
|
||||
{ self', ... }:
|
||||
{
|
||||
packages.default = self'.packages.continuwuity-default-bin;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
packages = {
|
||||
rocksdb = pkgs.callPackage ./package.nix { };
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
|
||||
rocksdb,
|
||||
liburing,
|
||||
rust-jemalloc-sys-unprefixed,
|
||||
|
||||
enableJemalloc ? false,
|
||||
enableLiburing ? false,
|
||||
|
||||
fetchFromGitea,
|
||||
|
||||
...
|
||||
}:
|
||||
let
|
||||
notDarwin = !stdenv.hostPlatform.isDarwin;
|
||||
in
|
||||
(rocksdb.override {
|
||||
# Override the liburing input for the build with our own so
|
||||
# we have it built with the library flag
|
||||
inherit liburing;
|
||||
jemalloc = rust-jemalloc-sys-unprefixed;
|
||||
|
||||
# rocksdb fails to build with prefixed jemalloc, which is required on
|
||||
# darwin due to [1]. In this case, fall back to building rocksdb with
|
||||
# libc malloc. This should not cause conflicts, because all of the
|
||||
# jemalloc symbols are prefixed.
|
||||
#
|
||||
# [1]: https://github.com/tikv/jemallocator/blob/ab0676d77e81268cd09b059260c75b38dbef2d51/jemalloc-sys/src/env.rs#L17
|
||||
enableJemalloc = enableJemalloc && notDarwin;
|
||||
|
||||
# for some reason enableLiburing in nixpkgs rocksdb is default true
|
||||
# which breaks Darwin entirely
|
||||
enableLiburing = enableLiburing && notDarwin;
|
||||
}).overrideAttrs
|
||||
(old: {
|
||||
src = fetchFromGitea {
|
||||
domain = "forgejo.ellis.link";
|
||||
owner = "continuwuation";
|
||||
repo = "rocksdb";
|
||||
rev = "10.5.fb";
|
||||
sha256 = "sha256-X4ApGLkHF9ceBtBg77dimEpu720I79ffLoyPa8JMHaU=";
|
||||
};
|
||||
version = "10.5.fb";
|
||||
cmakeFlags =
|
||||
lib.subtractLists (builtins.map (flag: lib.cmakeBool flag true) [
|
||||
# No real reason to have snappy or zlib, no one uses this
|
||||
"WITH_SNAPPY"
|
||||
"ZLIB"
|
||||
"WITH_ZLIB"
|
||||
# We don't need to use ldb or sst_dump (core_tools)
|
||||
"WITH_CORE_TOOLS"
|
||||
# We don't need to build rocksdb tests
|
||||
"WITH_TESTS"
|
||||
# We use rust-rocksdb via C interface and don't need C++ RTTI
|
||||
"USE_RTTI"
|
||||
# This doesn't exist in RocksDB, and USE_SSE is deprecated for
|
||||
# PORTABLE=$(march)
|
||||
"FORCE_SSE42"
|
||||
]) old.cmakeFlags
|
||||
++ (builtins.map (flag: lib.cmakeBool flag false) [
|
||||
# No real reason to have snappy, no one uses this
|
||||
"WITH_SNAPPY"
|
||||
"ZLIB"
|
||||
"WITH_ZLIB"
|
||||
# We don't need to use ldb or sst_dump (core_tools)
|
||||
"WITH_CORE_TOOLS"
|
||||
# We don't need trace tools
|
||||
"WITH_TRACE_TOOLS"
|
||||
# We don't need to build rocksdb tests
|
||||
"WITH_TESTS"
|
||||
# We use rust-rocksdb via C interface and don't need C++ RTTI
|
||||
"USE_RTTI"
|
||||
]);
|
||||
|
||||
enableLiburing = enableLiburing && notDarwin;
|
||||
|
||||
# outputs has "tools" which we don't need or use
|
||||
outputs = [ "out" ];
|
||||
|
||||
# preInstall hooks has stuff for messing with ldb/sst_dump which we don't need or use
|
||||
preInstall = "";
|
||||
|
||||
# We have this already at https://forgejo.ellis.link/continuwuation/rocksdb/commit/a935c0273e1ba44eacf88ce3685a9b9831486155
|
||||
# Unsetting `patches` so we don't have to revert it and make this nix exclusive
|
||||
patches = [ ];
|
||||
})
|
||||
@@ -0,0 +1,32 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
system,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
packages =
|
||||
let
|
||||
fnx = inputs.fenix.packages.${system};
|
||||
|
||||
stable = fnx.fromToolchainFile {
|
||||
file = inputs.self + "/rust-toolchain.toml";
|
||||
|
||||
# See also `rust-toolchain.toml`
|
||||
sha256 = "sha256-+9FmLhAOezBZCOziO0Qct1NOrfpjNsXxc/8I0c7BdKE=";
|
||||
};
|
||||
in
|
||||
{
|
||||
# used for building nix stuff (doesn't include rustfmt overhead)
|
||||
build-toolchain = stable;
|
||||
# used for dev shells
|
||||
dev-toolchain = fnx.combine [
|
||||
stable
|
||||
# use the nightly rustfmt because we use nightly features
|
||||
fnx.complete.rustfmt
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
args@{ pkgs, inputs, ... }:
|
||||
let
|
||||
inherit (pkgs) lib;
|
||||
uwuenv = import ./environment.nix args;
|
||||
selfpkgs = inputs.self.packages.${pkgs.stdenv.system};
|
||||
in
|
||||
rec {
|
||||
# basic, very minimal instance of the crane library with a minimal rust toolchain
|
||||
craneLib = (inputs.crane.mkLib pkgs).overrideToolchain (_: selfpkgs.build-toolchain);
|
||||
# the checks require more rust toolchain components, hence we have this separate instance of the crane library
|
||||
craneLibForChecks = (inputs.crane.mkLib pkgs).overrideToolchain (_: selfpkgs.dev-toolchain);
|
||||
|
||||
# meta information (name, version, etc) of the rust crate based on the Cargo.toml
|
||||
crateInfo = craneLib.crateNameFromCargoToml { cargoToml = "${inputs.self}/Cargo.toml"; };
|
||||
|
||||
src =
|
||||
let
|
||||
# see https://crane.dev/API.html#cranelibfiltercargosources
|
||||
#
|
||||
# we need to keep the `web` directory which would be filtered out by the regular source filtering function
|
||||
#
|
||||
# https://crane.dev/API.html#cranelibcleancargosource
|
||||
isWebTemplate = path: _type: builtins.match ".*src/web.*" path != null;
|
||||
isRust = craneLib.filterCargoSources;
|
||||
isNix = path: _type: builtins.match ".+/nix.*" path != null;
|
||||
webOrRustNotNix = p: t: !(isNix p t) && (isWebTemplate p t || isRust p t);
|
||||
in
|
||||
lib.cleanSourceWith {
|
||||
src = inputs.self;
|
||||
filter = webOrRustNotNix;
|
||||
name = "source";
|
||||
};
|
||||
|
||||
# common attrs that are shared between building continuwuity's deps and the package itself
|
||||
commonAttrs =
|
||||
{
|
||||
profile ? "dev",
|
||||
...
|
||||
}:
|
||||
{
|
||||
inherit (crateInfo)
|
||||
pname
|
||||
version
|
||||
;
|
||||
inherit src;
|
||||
|
||||
# this prevents unnecessary rebuilds
|
||||
strictDeps = true;
|
||||
|
||||
dontStrip = profile == "dev" || profile == "test";
|
||||
dontPatchELF = profile == "dev" || profile == "test";
|
||||
|
||||
doCheck = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
# bindgen needs the build platform's libclang. Apparently due to "splicing
|
||||
# weirdness", pkgs.rustPlatform.bindgenHook on its own doesn't quite do the
|
||||
# right thing here.
|
||||
pkgs.rustPlatform.bindgenHook
|
||||
];
|
||||
};
|
||||
|
||||
makeRocksDBEnv =
|
||||
{ rocksdb }:
|
||||
{
|
||||
ROCKSDB_INCLUDE_DIR = "${rocksdb}/include";
|
||||
ROCKSDB_LIB_DIR = "${rocksdb}/lib";
|
||||
};
|
||||
|
||||
# function that builds the continuwuity dependencies derivation
|
||||
buildDeps =
|
||||
{
|
||||
rocksdb,
|
||||
features,
|
||||
commonAttrsArgs,
|
||||
}:
|
||||
craneLib.buildDepsOnly (
|
||||
(commonAttrs commonAttrsArgs)
|
||||
// {
|
||||
env = uwuenv.buildDepsOnlyEnv // (makeRocksDBEnv { inherit rocksdb; });
|
||||
inherit (features) cargoExtraArgs;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
# function that builds the continuwuity package
|
||||
buildPackage =
|
||||
{
|
||||
deps,
|
||||
rocksdb,
|
||||
features,
|
||||
commonAttrsArgs,
|
||||
}:
|
||||
let
|
||||
rocksdbEnv = makeRocksDBEnv { inherit rocksdb; };
|
||||
in
|
||||
craneLib.buildPackage (
|
||||
(commonAttrs commonAttrsArgs)
|
||||
// {
|
||||
cargoArtifacts = deps;
|
||||
doCheck = true;
|
||||
env = uwuenv.buildPackageEnv // rocksdbEnv;
|
||||
passthru.env = uwuenv.buildPackageEnv // rocksdbEnv;
|
||||
meta.mainProgram = crateInfo.pname;
|
||||
inherit (features) cargoExtraArgs;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
flake.uwulib = {
|
||||
init = pkgs: {
|
||||
features = import ./features.nix { inherit pkgs inputs; };
|
||||
environment = import ./environment.nix { inherit pkgs inputs; };
|
||||
build = import ./build.nix { inherit pkgs inputs; };
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
args@{ pkgs, inputs, ... }:
|
||||
let
|
||||
uwubuild = import ./build.nix args;
|
||||
in
|
||||
rec {
|
||||
buildDepsOnlyEnv = {
|
||||
# https://crane.dev/faq/rebuilds-bindgen.html
|
||||
NIX_OUTPATH_USED_AS_RANDOM_SEED = "aaaaaaaaaa";
|
||||
CARGO_PROFILE = "release";
|
||||
}
|
||||
// uwubuild.craneLib.mkCrossToolchainEnv (p: pkgs.clangStdenv);
|
||||
|
||||
buildPackageEnv = {
|
||||
GIT_COMMIT_HASH = inputs.self.rev or inputs.self.dirtyRev or "";
|
||||
GIT_COMMIT_HASH_SHORT = inputs.self.shortRev or inputs.self.dirtyShortRev or "";
|
||||
}
|
||||
// buildDepsOnlyEnv;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
{ pkgs, inputs, ... }:
|
||||
let
|
||||
inherit (pkgs) lib;
|
||||
in
|
||||
rec {
|
||||
defaultDisabledFeatures = [
|
||||
# dont include experimental features
|
||||
"experimental"
|
||||
# jemalloc profiling/stats features are expensive and shouldn't
|
||||
# be expected on non-debug builds.
|
||||
"jemalloc_prof"
|
||||
"jemalloc_stats"
|
||||
# this is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
# we don't want to enable this feature set by default but be more specific about it
|
||||
"full"
|
||||
];
|
||||
# We perform default-feature unification in nix, because some of the dependencies
|
||||
# on the nix side depend on feature values.
|
||||
calcFeatures =
|
||||
{
|
||||
tomlPath ? "${inputs.self}/src/main",
|
||||
# either a list of feature names or a string "all" which enables all non-default features
|
||||
enabledFeatures ? [ ],
|
||||
disabledFeatures ? defaultDisabledFeatures,
|
||||
default_features ? true,
|
||||
disable_release_max_log_level ? false,
|
||||
}:
|
||||
let
|
||||
# simple helper to get the contents of a Cargo.toml file in a nix format
|
||||
getToml = path: lib.importTOML "${path}/Cargo.toml";
|
||||
|
||||
# get all the features except for the default features
|
||||
allFeatures = lib.pipe tomlPath [
|
||||
getToml
|
||||
(manifest: manifest.features)
|
||||
lib.attrNames
|
||||
(lib.remove "default")
|
||||
];
|
||||
|
||||
# get just the default enabled features
|
||||
allDefaultFeatures = lib.pipe tomlPath [
|
||||
getToml
|
||||
(manifest: manifest.features.default)
|
||||
];
|
||||
|
||||
# depending on the value of enabledFeatures choose just a set or all non-default features
|
||||
#
|
||||
# - [ list of features ] -> choose exactly the features listed
|
||||
# - "all" -> choose all non-default features
|
||||
additionalFeatures = if enabledFeatures == "all" then allFeatures else enabledFeatures;
|
||||
|
||||
# unification with default features (if enabled)
|
||||
features = lib.unique (additionalFeatures ++ lib.optionals default_features allDefaultFeatures);
|
||||
|
||||
# prepare the features that are subtracted from the set
|
||||
disabledFeatures' =
|
||||
disabledFeatures ++ lib.optionals disable_release_max_log_level [ "release_max_log_level" ];
|
||||
|
||||
# construct the final feature set
|
||||
finalFeatures = lib.subtractLists disabledFeatures' features;
|
||||
in
|
||||
{
|
||||
# final feature set, useful for querying it
|
||||
features = finalFeatures;
|
||||
|
||||
# crane flag with the relevant features
|
||||
cargoExtraArgs = builtins.concatStringsSep " " [
|
||||
"--no-default-features"
|
||||
"--locked"
|
||||
(lib.optionalString (finalFeatures != [ ]) "--features")
|
||||
(builtins.concatStringsSep "," finalFeatures)
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
self',
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
uwulib = inputs.self.uwulib.init pkgs;
|
||||
rocksdbAllFeatures = self'.packages.rocksdb.override {
|
||||
enableJemalloc = true;
|
||||
enableLiburing = true;
|
||||
};
|
||||
in
|
||||
{
|
||||
# basic nix shell containing all things necessary to build continuwuity in all flavors manually (on x86_64-linux)
|
||||
devShells.default = uwulib.build.craneLib.devShell {
|
||||
packages = [
|
||||
pkgs.pkg-config
|
||||
pkgs.liburing
|
||||
pkgs.rust-jemalloc-sys-unprefixed
|
||||
rocksdbAllFeatures
|
||||
];
|
||||
env.LIBCLANG_PATH = lib.makeLibraryPath [ pkgs.llvmPackages.libclang.lib ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
self',
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
# run some nixos tests as checks
|
||||
checks = lib.pipe self'.packages [
|
||||
# we take all packages (names)
|
||||
builtins.attrNames
|
||||
# we filter out all packages that end with `-bin` (which we are interested in for testing)
|
||||
(builtins.filter (lib.hasSuffix "-bin"))
|
||||
# for each of these binaries we built the basic nixos test
|
||||
#
|
||||
# this test was initially yoinked from
|
||||
#
|
||||
# https://github.com/NixOS/nixpkgs/blob/960ce26339661b1b69c6f12b9063ca51b688615f/nixos/tests/matrix/continuwuity.nix
|
||||
(builtins.map (name: {
|
||||
name = "test-${name}";
|
||||
value = pkgs.testers.runNixOSTest {
|
||||
inherit name;
|
||||
|
||||
nodes = {
|
||||
continuwuity = {
|
||||
services.matrix-continuwuity = {
|
||||
enable = true;
|
||||
package = self'.packages.${name};
|
||||
settings.global = {
|
||||
server_name = name;
|
||||
address = [ "0.0.0.0" ];
|
||||
allow_registration = true;
|
||||
yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = true;
|
||||
};
|
||||
extraEnvironment.RUST_BACKTRACE = "yes";
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 6167 ];
|
||||
};
|
||||
client =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [
|
||||
(pkgs.writers.writePython3Bin "do_test" { libraries = [ pkgs.python3Packages.matrix-nio ]; } ''
|
||||
import asyncio
|
||||
import nio
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# Connect to continuwuity
|
||||
client = nio.AsyncClient("http://continuwuity:6167", "alice")
|
||||
|
||||
# Register as user alice
|
||||
response = await client.register("alice", "my-secret-password")
|
||||
|
||||
# Log in as user alice
|
||||
response = await client.login("my-secret-password")
|
||||
|
||||
# Create a new room
|
||||
response = await client.room_create(federate=False)
|
||||
print("Matrix room create response:", response)
|
||||
assert isinstance(response, nio.RoomCreateResponse)
|
||||
room_id = response.room_id
|
||||
|
||||
# Join the room
|
||||
response = await client.join(room_id)
|
||||
print("Matrix join response:", response)
|
||||
assert isinstance(response, nio.JoinResponse)
|
||||
|
||||
# Send a message to the room
|
||||
response = await client.room_send(
|
||||
room_id=room_id,
|
||||
message_type="m.room.message",
|
||||
content={
|
||||
"msgtype": "m.text",
|
||||
"body": "Hello continuwuity!"
|
||||
}
|
||||
)
|
||||
print("Matrix room send response:", response)
|
||||
assert isinstance(response, nio.RoomSendResponse)
|
||||
|
||||
# Sync responses
|
||||
response = await client.sync(timeout=30000)
|
||||
print("Matrix sync response:", response)
|
||||
assert isinstance(response, nio.SyncResponse)
|
||||
|
||||
# Check the message was received by continuwuity
|
||||
last_message = response.rooms.join[room_id].timeline.events[-1].body
|
||||
assert last_message == "Hello continuwuity!"
|
||||
|
||||
# Leave the room
|
||||
response = await client.room_leave(room_id)
|
||||
print("Matrix room leave response:", response)
|
||||
assert isinstance(response, nio.RoomLeaveResponse)
|
||||
|
||||
# Close the client
|
||||
await client.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
with subtest("start continuwuity"):
|
||||
continuwuity.wait_for_unit("continuwuity.service")
|
||||
continuwuity.wait_for_open_port(6167)
|
||||
|
||||
with subtest("ensure messages can be exchanged"):
|
||||
client.succeed("do_test >&2")
|
||||
'';
|
||||
|
||||
};
|
||||
}))
|
||||
builtins.listToAttrs
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -12,13 +12,14 @@ Group=conduwuit
|
||||
Type=notify-reload
|
||||
ReloadSignal=SIGUSR1
|
||||
|
||||
Environment="CONTINUWUITY_CONFIG=/etc/conduwuit/conduwuit.toml"
|
||||
|
||||
Environment="CONTINUWUITY_LOG_TO_JOURNALD=true"
|
||||
Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N"
|
||||
Environment="CONTINUWUITY_DATABASE_PATH=/var/lib/conduwuit"
|
||||
Environment="CONTINUWUITY_DATABASE_PATH=%S/conduwuit"
|
||||
Environment="CONTINUWUITY_CONFIG_RELOAD_SIGNAL=true"
|
||||
|
||||
ExecStart=/usr/bin/conduwuit
|
||||
LoadCredential=conduwuit.toml:/etc/conduwuit/conduwuit.toml
|
||||
|
||||
ExecStart=/usr/bin/conduwuit --config ${CREDENTIALS_DIRECTORY}/conduwuit.toml
|
||||
|
||||
AmbientCapabilities=
|
||||
CapabilityBoundingSet=
|
||||
@@ -52,8 +53,9 @@ SystemCallFilter=@system-service @resources
|
||||
SystemCallFilter=~@clock @debug @module @mount @reboot @swap @cpu-emulation @obsolete @timer @chown @setuid @privileged @keyring @ipc
|
||||
SystemCallErrorNumber=EPERM
|
||||
|
||||
# ConfigurationDirectory isn't specified here because it's created by
|
||||
# the distro's package manager.
|
||||
StateDirectory=conduwuit
|
||||
ConfigurationDirectory=conduwuit
|
||||
RuntimeDirectory=conduwuit
|
||||
RuntimeDirectoryMode=0750
|
||||
|
||||
|
||||
+20
-4
@@ -1,12 +1,28 @@
|
||||
# Continuwuity for Debian
|
||||
|
||||
This document provides information about downloading and deploying the Debian package. You can also use this guide for other `apt`-based distributions such as Ubuntu.
|
||||
This document provides information about downloading and deploying the Debian package. You can also use this guide for other deb-based distributions such as Ubuntu.
|
||||
|
||||
### Installation
|
||||
|
||||
See the [generic deployment guide](../deploying/generic.md) for additional information about using the Debian package.
|
||||
To add the Continuwuation apt repository:
|
||||
```bash
|
||||
# Replace with `"dev"` for bleeding-edge builds at your own risk
|
||||
export COMPONENT="stable"
|
||||
# Import the Continuwuation signing key
|
||||
sudo curl https://forgejo.ellis.link/api/packages/continuwuation/debian/repository.key -o /etc/apt/keyrings/forgejo-continuwuation.asc
|
||||
# Add a new apt source list pointing to the repository
|
||||
echo "deb [signed-by=/etc/apt/keyrings/forgejo-continuwuation.asc] https://forgejo.ellis.link/api/packages/continuwuation/debian $(lsb_release -sc) $COMPONENT" | sudo tee /etc/apt/sources.list.d/continuwuation.list
|
||||
# Update remote package lists
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
No `apt` repository is currently available. This feature is in development.
|
||||
To install continuwuity:
|
||||
```bash
|
||||
sudo apt install continuwuity
|
||||
```
|
||||
The `continuwuity` package conflicts with the old `conduwuit` package and will remove it automatically when installed.
|
||||
|
||||
See the [generic deployment guide](../deploying/generic.md) for additional information about using the Debian package.
|
||||
|
||||
### Configuration
|
||||
|
||||
@@ -16,7 +32,7 @@ You can customize additional settings by uncommenting and modifying the configur
|
||||
|
||||
### Running
|
||||
|
||||
The package uses the [`conduwuit.service`](../configuration/examples.md#example-systemd-unit-file) systemd unit file to start and stop Continuwuity. The binary installs at `/usr/sbin/conduwuit`.
|
||||
The package uses the [`conduwuit.service`](../configuration/examples.md#example-systemd-unit-file) systemd unit file to start and stop Continuwuity. The binary installs at `/usr/bin/conduwuit`.
|
||||
|
||||
By default, this package assumes that Continuwuity runs behind a reverse proxy. The default configuration options apply (listening on `localhost` and TCP port `6167`). Matrix federation requires a valid domain name and TLS. To federate properly, you must set up TLS certificates and certificate renewal.
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# This should be run using rpkg-util: https://docs.pagure.org/rpkg-util
|
||||
# This should be run using rpkg: https://docs.pagure.org/rpkg
|
||||
# it requires Internet access and is not suitable for Fedora main repos
|
||||
# TODO: rpkg-util is no longer maintained, find a replacement
|
||||
|
||||
Name: continuwuity
|
||||
Version: {{{ git_repo_version }}}
|
||||
@@ -52,7 +51,7 @@ find .cargo/registry/ -executable -name "*.rs" -exec chmod -x {} +
|
||||
%install
|
||||
install -Dpm0755 target/rpm/conduwuit -t %{buildroot}%{_bindir}
|
||||
install -Dpm0644 pkg/conduwuit.service -t %{buildroot}%{_unitdir}
|
||||
install -Dpm0644 conduwuit-example.toml %{buildroot}%{_sysconfdir}/conduwuit/conduwuit.toml
|
||||
install -Dpm0600 conduwuit-example.toml %{buildroot}%{_sysconfdir}/conduwuit/conduwuit.toml
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
@@ -61,7 +60,7 @@ install -Dpm0644 conduwuit-example.toml %{buildroot}%{_sysconfdir}/conduwuit/con
|
||||
%doc CONTRIBUTING.md
|
||||
%doc README.md
|
||||
%doc SECURITY.md
|
||||
%config %{_sysconfdir}/conduwuit/conduwuit.toml
|
||||
%config(noreplace) %{_sysconfdir}/conduwuit/conduwuit.toml
|
||||
|
||||
%{_bindir}/conduwuit
|
||||
%{_unitdir}/conduwuit.service
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
{ lib
|
||||
, pkgsBuildHost
|
||||
, rust
|
||||
, stdenv
|
||||
}:
|
||||
|
||||
lib.optionalAttrs stdenv.hostPlatform.isStatic
|
||||
{
|
||||
ROCKSDB_STATIC = "";
|
||||
}
|
||||
//
|
||||
{
|
||||
CARGO_BUILD_RUSTFLAGS =
|
||||
lib.concatStringsSep
|
||||
" "
|
||||
(lib.optionals
|
||||
stdenv.hostPlatform.isStatic
|
||||
[ "-C" "relocation-model=static" ]
|
||||
++ lib.optionals
|
||||
(stdenv.buildPlatform.config != stdenv.hostPlatform.config)
|
||||
[
|
||||
"-l"
|
||||
"c"
|
||||
|
||||
"-l"
|
||||
"stdc++"
|
||||
|
||||
"-L"
|
||||
"${stdenv.cc.cc.lib}/${stdenv.hostPlatform.config}/lib"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
# What follows is stolen from [here][0]. Its purpose is to properly
|
||||
# configure compilers and linkers for various stages of the build, and
|
||||
# even covers the case of build scripts that need native code compiled and
|
||||
# run on the build platform (I think).
|
||||
#
|
||||
# [0]: https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/build-support/rust/lib/default.nix#L48-L68
|
||||
//
|
||||
(
|
||||
let
|
||||
inherit (rust.lib) envVars;
|
||||
in
|
||||
lib.optionalAttrs
|
||||
(stdenv.targetPlatform.rust.rustcTarget
|
||||
!= stdenv.hostPlatform.rust.rustcTarget)
|
||||
(
|
||||
let
|
||||
inherit (stdenv.targetPlatform.rust) cargoEnvVarTarget;
|
||||
in
|
||||
{
|
||||
"CC_${cargoEnvVarTarget}" = envVars.ccForTarget;
|
||||
"CXX_${cargoEnvVarTarget}" = envVars.cxxForTarget;
|
||||
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForTarget;
|
||||
}
|
||||
)
|
||||
//
|
||||
(
|
||||
let
|
||||
inherit (stdenv.hostPlatform.rust) cargoEnvVarTarget rustcTarget;
|
||||
in
|
||||
{
|
||||
"CC_${cargoEnvVarTarget}" = envVars.ccForHost;
|
||||
"CXX_${cargoEnvVarTarget}" = envVars.cxxForHost;
|
||||
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForHost;
|
||||
CARGO_BUILD_TARGET = rustcTarget;
|
||||
}
|
||||
)
|
||||
//
|
||||
(
|
||||
let
|
||||
inherit (stdenv.buildPlatform.rust) cargoEnvVarTarget;
|
||||
in
|
||||
{
|
||||
"CC_${cargoEnvVarTarget}" = envVars.ccForBuild;
|
||||
"CXX_${cargoEnvVarTarget}" = envVars.cxxForBuild;
|
||||
"CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.ccForBuild;
|
||||
HOST_CC = "${pkgsBuildHost.stdenv.cc}/bin/cc";
|
||||
HOST_CXX = "${pkgsBuildHost.stdenv.cc}/bin/c++";
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -1,224 +0,0 @@
|
||||
# Dependencies (keep sorted)
|
||||
{ craneLib
|
||||
, inputs
|
||||
, jq
|
||||
, lib
|
||||
, libiconv
|
||||
, liburing
|
||||
, pkgsBuildHost
|
||||
, rocksdb
|
||||
, removeReferencesTo
|
||||
, rust
|
||||
, rust-jemalloc-sys
|
||||
, stdenv
|
||||
|
||||
# Options (keep sorted)
|
||||
, all_features ? false
|
||||
, default_features ? true
|
||||
# default list of disabled features
|
||||
, disable_features ? [
|
||||
# dont include experimental features
|
||||
"experimental"
|
||||
# jemalloc profiling/stats features are expensive and shouldn't
|
||||
# be expected on non-debug builds.
|
||||
"jemalloc_prof"
|
||||
"jemalloc_stats"
|
||||
# this is non-functional on nix for some reason
|
||||
"hardened_malloc"
|
||||
# conduwuit_mods is a development-only hot reload feature
|
||||
"conduwuit_mods"
|
||||
]
|
||||
, disable_release_max_log_level ? false
|
||||
, features ? [ ]
|
||||
, profile ? "release"
|
||||
# rocksdb compiled with -march=haswell and target-cpu=haswell rustflag
|
||||
# haswell is pretty much any x86 cpu made in the last 12 years, and
|
||||
# supports modern CPU extensions that rocksdb can make use of.
|
||||
# disable if trying to make a portable x86_64 build for very old hardware
|
||||
, x86_64_haswell_target_optimised ? false
|
||||
}:
|
||||
|
||||
let
|
||||
# We perform default-feature unification in nix, because some of the dependencies
|
||||
# on the nix side depend on feature values.
|
||||
crateFeatures = path:
|
||||
let manifest = lib.importTOML "${path}/Cargo.toml"; in
|
||||
lib.remove "default" (lib.attrNames manifest.features);
|
||||
crateDefaultFeatures = path:
|
||||
(lib.importTOML "${path}/Cargo.toml").features.default;
|
||||
allDefaultFeatures = crateDefaultFeatures "${inputs.self}/src/main";
|
||||
allFeatures = crateFeatures "${inputs.self}/src/main";
|
||||
features' = lib.unique
|
||||
(features ++
|
||||
lib.optionals default_features allDefaultFeatures ++
|
||||
lib.optionals all_features allFeatures);
|
||||
disable_features' = disable_features ++ lib.optionals disable_release_max_log_level [ "release_max_log_level" ];
|
||||
features'' = lib.subtractLists disable_features' features';
|
||||
|
||||
featureEnabled = feature: builtins.elem feature features'';
|
||||
|
||||
enableLiburing = featureEnabled "io_uring" && !stdenv.hostPlatform.isDarwin;
|
||||
|
||||
# This derivation will set the JEMALLOC_OVERRIDE variable, causing the
|
||||
# tikv-jemalloc-sys crate to use the nixpkgs jemalloc instead of building it's
|
||||
# own. In order for this to work, we need to set flags on the build that match
|
||||
# whatever flags tikv-jemalloc-sys was going to use. These are dependent on
|
||||
# which features we enable in tikv-jemalloc-sys.
|
||||
rust-jemalloc-sys' = (rust-jemalloc-sys.override {
|
||||
# tikv-jemalloc-sys/unprefixed_malloc_on_supported_platforms feature
|
||||
unprefixed = true;
|
||||
}).overrideAttrs (old: {
|
||||
configureFlags = old.configureFlags ++
|
||||
# we dont need docs
|
||||
[ "--disable-doc" ] ++
|
||||
# we dont need cxx/C++ integration
|
||||
[ "--disable-cxx" ] ++
|
||||
# tikv-jemalloc-sys/profiling feature
|
||||
lib.optional (featureEnabled "jemalloc_prof") "--enable-prof" ++
|
||||
# tikv-jemalloc-sys/stats feature
|
||||
(if (featureEnabled "jemalloc_stats") then [ "--enable-stats" ] else [ "--disable-stats" ]);
|
||||
});
|
||||
|
||||
buildDepsOnlyEnv =
|
||||
let
|
||||
rocksdb' = (rocksdb.override {
|
||||
jemalloc = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys';
|
||||
# rocksdb fails to build with prefixed jemalloc, which is required on
|
||||
# darwin due to [1]. In this case, fall back to building rocksdb with
|
||||
# libc malloc. This should not cause conflicts, because all of the
|
||||
# jemalloc symbols are prefixed.
|
||||
#
|
||||
# [1]: https://github.com/tikv/jemallocator/blob/ab0676d77e81268cd09b059260c75b38dbef2d51/jemalloc-sys/src/env.rs#L17
|
||||
enableJemalloc = featureEnabled "jemalloc" && !stdenv.hostPlatform.isDarwin;
|
||||
|
||||
# for some reason enableLiburing in nixpkgs rocksdb is default true
|
||||
# which breaks Darwin entirely
|
||||
inherit enableLiburing;
|
||||
}).overrideAttrs (old: {
|
||||
inherit enableLiburing;
|
||||
cmakeFlags = (if x86_64_haswell_target_optimised then
|
||||
(lib.subtractLists [
|
||||
# dont make a portable build if x86_64_haswell_target_optimised is enabled
|
||||
"-DPORTABLE=1"
|
||||
]
|
||||
old.cmakeFlags
|
||||
++ [ "-DPORTABLE=haswell" ]) else [ "-DPORTABLE=1" ]
|
||||
)
|
||||
++ old.cmakeFlags;
|
||||
|
||||
# outputs has "tools" which we dont need or use
|
||||
outputs = [ "out" ];
|
||||
|
||||
# preInstall hooks has stuff for messing with ldb/sst_dump which we dont need or use
|
||||
preInstall = "";
|
||||
});
|
||||
in
|
||||
{
|
||||
# https://crane.dev/faq/rebuilds-bindgen.html
|
||||
NIX_OUTPATH_USED_AS_RANDOM_SEED = "aaaaaaaaaa";
|
||||
|
||||
CARGO_PROFILE = profile;
|
||||
ROCKSDB_INCLUDE_DIR = "${rocksdb'}/include";
|
||||
ROCKSDB_LIB_DIR = "${rocksdb'}/lib";
|
||||
}
|
||||
//
|
||||
(import ./cross-compilation-env.nix {
|
||||
# Keep sorted
|
||||
inherit
|
||||
lib
|
||||
pkgsBuildHost
|
||||
rust
|
||||
stdenv;
|
||||
});
|
||||
|
||||
buildPackageEnv = {
|
||||
GIT_COMMIT_HASH = inputs.self.rev or inputs.self.dirtyRev or "";
|
||||
GIT_COMMIT_HASH_SHORT = inputs.self.shortRev or inputs.self.dirtyShortRev or "";
|
||||
} // buildDepsOnlyEnv // {
|
||||
# Only needed in static stdenv because these are transitive dependencies of rocksdb
|
||||
CARGO_BUILD_RUSTFLAGS = buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS
|
||||
+ lib.optionalString (enableLiburing && stdenv.hostPlatform.isStatic)
|
||||
" -L${lib.getLib liburing}/lib -luring"
|
||||
+ lib.optionalString x86_64_haswell_target_optimised
|
||||
" -Ctarget-cpu=haswell";
|
||||
};
|
||||
|
||||
|
||||
|
||||
commonAttrs = {
|
||||
inherit
|
||||
(craneLib.crateNameFromCargoToml {
|
||||
cargoToml = "${inputs.self}/Cargo.toml";
|
||||
})
|
||||
pname
|
||||
version;
|
||||
|
||||
src = let filter = inputs.nix-filter.lib; in filter {
|
||||
root = inputs.self;
|
||||
|
||||
# Keep sorted
|
||||
include = [
|
||||
".cargo"
|
||||
"Cargo.lock"
|
||||
"Cargo.toml"
|
||||
"src"
|
||||
"xtask"
|
||||
];
|
||||
};
|
||||
|
||||
doCheck = true;
|
||||
|
||||
cargoExtraArgs = "--no-default-features --locked "
|
||||
+ lib.optionalString
|
||||
(features'' != [ ])
|
||||
"--features " + (builtins.concatStringsSep "," features'');
|
||||
|
||||
dontStrip = profile == "dev" || profile == "test";
|
||||
dontPatchELF = profile == "dev" || profile == "test";
|
||||
|
||||
buildInputs = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys'
|
||||
# needed to build Rust applications on macOS
|
||||
++ lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
# https://github.com/NixOS/nixpkgs/issues/206242
|
||||
# ld: library not found for -liconv
|
||||
libiconv
|
||||
# https://stackoverflow.com/questions/69869574/properly-adding-darwin-apple-sdk-to-a-nix-shell
|
||||
# https://discourse.nixos.org/t/compile-a-rust-binary-on-macos-dbcrossbar/8612
|
||||
pkgsBuildHost.darwin.apple_sdk.frameworks.Security
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
# bindgen needs the build platform's libclang. Apparently due to "splicing
|
||||
# weirdness", pkgs.rustPlatform.bindgenHook on its own doesn't quite do the
|
||||
# right thing here.
|
||||
pkgsBuildHost.rustPlatform.bindgenHook
|
||||
|
||||
# We don't actually depend on `jq`, but crane's `buildPackage` does, but
|
||||
# its `buildDepsOnly` doesn't. This causes those two derivations to have
|
||||
# differing values for `NIX_CFLAGS_COMPILE`, which contributes to spurious
|
||||
# rebuilds of bindgen and its depedents.
|
||||
jq
|
||||
];
|
||||
};
|
||||
in
|
||||
|
||||
craneLib.buildPackage (commonAttrs // {
|
||||
cargoArtifacts = craneLib.buildDepsOnly (commonAttrs // {
|
||||
env = buildDepsOnlyEnv;
|
||||
});
|
||||
|
||||
doCheck = true;
|
||||
|
||||
cargoExtraArgs = "--no-default-features --locked "
|
||||
+ lib.optionalString
|
||||
(features'' != [ ])
|
||||
"--features " + (builtins.concatStringsSep "," features'');
|
||||
|
||||
env = buildPackageEnv;
|
||||
|
||||
passthru = {
|
||||
env = buildPackageEnv;
|
||||
};
|
||||
|
||||
meta.mainProgram = commonAttrs.pname;
|
||||
})
|
||||
+11
-11
@@ -10,15 +10,19 @@
|
||||
"nix": {
|
||||
"enabled": true
|
||||
},
|
||||
"pre-commit": {
|
||||
"enabled": true
|
||||
},
|
||||
"labels": ["Dependencies", "Dependencies/Renovate"],
|
||||
"ignoreDeps": [
|
||||
"tikv-jemallocator",
|
||||
"tikv-jemalloc-sys",
|
||||
"tikv-jemalloc-ctl",
|
||||
"opentelemetry",
|
||||
"opentelemetry_sdk",
|
||||
"opentelemetry-jaeger",
|
||||
"tracing-opentelemetry"
|
||||
"rustyline-async",
|
||||
"event-listener",
|
||||
"async-channel",
|
||||
"core_affinity",
|
||||
"hyper-util"
|
||||
],
|
||||
"github-actions": {
|
||||
"enabled": true,
|
||||
@@ -64,12 +68,8 @@
|
||||
"matchDatasources": ["docker"],
|
||||
"matchPackageNames": ["ghcr.io/renovatebot/renovate"],
|
||||
"automerge": true,
|
||||
"automergeStrategy": "fast-forward"
|
||||
},
|
||||
{
|
||||
"description": "Group lockfile updates into a single PR",
|
||||
"matchUpdateTypes": ["lockFileMaintenance"],
|
||||
"groupName": "lockfile-maintenance"
|
||||
"automergeStrategy": "fast-forward",
|
||||
"extends": ["schedule:earlyMondays"]
|
||||
}
|
||||
],
|
||||
"customManagers": [
|
||||
@@ -81,7 +81,7 @@
|
||||
"/(^|/|\\.)([Dd]ocker|[Cc]ontainer)file$/"
|
||||
],
|
||||
"matchStrings": [
|
||||
"# renovate: datasource=(?<datasource>[a-z-.]+?) depName=(?<depName>[^\\s]+?)(?: (lookupName|packageName)=(?<packageName>[^\\s]+?))?(?: versioning=(?<versioning>[^\\s]+?))?(?: extractVersion=(?<extractVersion>[^\\s]+?))?(?: registryUrl=(?<registryUrl>[^\\s]+?))?\\s+(?:ENV|ARG)\\s+[A-Za-z0-9_]+?_VERSION[ =][\"']?(?<currentValue>.+?)[\"']?\\s"
|
||||
"# renovate: datasource=(?<datasource>[a-zA-Z0-9-._]+?) depName=(?<depName>[^\\s]+?)(?: (lookupName|packageName)=(?<packageName>[^\\s]+?))?(?: versioning=(?<versioning>[^\\s]+?))?(?: extractVersion=(?<extractVersion>[^\\s]+?))?(?: registryUrl=(?<registryUrl>[^\\s]+?))?\\s+(?:ENV\\s+|ARG\\s+)?[A-Za-z0-9_]+?_VERSION[ =][\"']?(?<currentValue>.+?)[\"']?\\s+(?:(?:ENV\\s+|ARG\\s+)?[A-Za-z0-9_]+?_CHECKSUM[ =][\"']?(?<currentDigest>.+?)[\"']?\\s)?"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -85,7 +85,7 @@ futures.workspace = true
|
||||
log.workspace = true
|
||||
ruma.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_yml.workspace = true
|
||||
serde-saphyr.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
@@ -16,7 +16,7 @@ pub(super) async fn register(&self) -> Result {
|
||||
|
||||
let range = 1..checked!(body_len - 1)?;
|
||||
let appservice_config_body = body[range].join("\n");
|
||||
let parsed_config = serde_yml::from_str(&appservice_config_body);
|
||||
let parsed_config = serde_saphyr::from_str(&appservice_config_body);
|
||||
match parsed_config {
|
||||
| Err(e) => return Err!("Could not parse appservice config as YAML: {e}"),
|
||||
| Ok(registration) => match self
|
||||
@@ -57,7 +57,7 @@ pub(super) async fn show_appservice_config(&self, appservice_identifier: String)
|
||||
{
|
||||
| None => return Err!("Appservice does not exist."),
|
||||
| Some(config) => {
|
||||
let config_str = serde_yml::to_string(&config)?;
|
||||
let config_str = serde_saphyr::to_string(&config)?;
|
||||
write!(self, "Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```")
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@ use std::time::Duration;
|
||||
|
||||
use conduwuit::{
|
||||
Err, Result, debug, debug_info, debug_warn, error, info, trace,
|
||||
utils::time::parse_timepoint_ago, warn,
|
||||
utils::time::{TimeDirection, parse_timepoint_ago},
|
||||
warn,
|
||||
};
|
||||
use conduwuit_service::media::Dim;
|
||||
use ruma::{Mxc, OwnedEventId, OwnedMxcUri, OwnedServerName};
|
||||
@@ -235,14 +236,19 @@ pub(super) async fn delete_past_remote_media(
|
||||
}
|
||||
assert!(!(before && after), "--before and --after should not be specified together");
|
||||
|
||||
let duration = parse_timepoint_ago(&duration)?;
|
||||
let direction = if after {
|
||||
TimeDirection::After
|
||||
} else {
|
||||
TimeDirection::Before
|
||||
};
|
||||
|
||||
let time_boundary = parse_timepoint_ago(&duration)?;
|
||||
let deleted_count = self
|
||||
.services
|
||||
.media
|
||||
.delete_all_remote_media_at_after_time(
|
||||
duration,
|
||||
before,
|
||||
after,
|
||||
.delete_all_media_within_timeframe(
|
||||
time_boundary,
|
||||
direction,
|
||||
yes_i_want_to_delete_local_media,
|
||||
)
|
||||
.await?;
|
||||
|
||||
+17
-5
@@ -27,12 +27,24 @@ pub enum MediaCommand {
|
||||
/// filesystem. This will always ignore errors.
|
||||
DeleteList,
|
||||
|
||||
/// - Deletes all remote (and optionally local) media created before or
|
||||
/// after [duration] time using filesystem metadata first created at date,
|
||||
/// or fallback to last modified date. This will always ignore errors by
|
||||
/// default.
|
||||
/// Deletes all remote (and optionally local) media created before/after
|
||||
/// [duration] ago, using filesystem metadata first created at date, or
|
||||
/// fallback to last modified date. This will always ignore errors by
|
||||
/// default.
|
||||
///
|
||||
/// * Examples:
|
||||
/// * Delete all remote media older than a year:
|
||||
///
|
||||
/// `!admin media delete-past-remote-media -b 1y`
|
||||
///
|
||||
/// * Delete all remote and local media from 3 days ago, up until now:
|
||||
///
|
||||
/// `!admin media delete-past-remote-media -a 3d
|
||||
/// --yes-i-want-to-delete-local-media`
|
||||
#[command(verbatim_doc_comment)]
|
||||
DeletePastRemoteMedia {
|
||||
/// - The relative time (e.g. 30s, 5m, 7d) within which to search
|
||||
/// - The relative time (e.g. 30s, 5m, 7d) from now within which to
|
||||
/// search
|
||||
duration: String,
|
||||
|
||||
/// - Only delete media created before [duration] ago
|
||||
|
||||
@@ -64,10 +64,14 @@ pub(crate) async fn create_content_route(
|
||||
media_id: &utils::random_string(MXC_LENGTH),
|
||||
};
|
||||
|
||||
services
|
||||
if let Err(e) = services
|
||||
.media
|
||||
.create(mxc, Some(user), Some(&content_disposition), content_type, &body.file)
|
||||
.await?;
|
||||
.await
|
||||
{
|
||||
err!("Failed to save uploaded media: {e}");
|
||||
return Err!(Request(Unknown("Failed to save uploaded media")));
|
||||
}
|
||||
|
||||
let blurhash = body.generate_blurhash.then(|| {
|
||||
services
|
||||
|
||||
@@ -97,11 +97,12 @@ pub(crate) async fn upgrade_room_route(
|
||||
|
||||
// Create a replacement room
|
||||
let room_features = RoomVersion::new(&body.new_version)?;
|
||||
let replacement_room: Option<&RoomId> = if room_features.room_ids_as_hashes {
|
||||
None
|
||||
let replacement_room_owned = if !room_features.room_ids_as_hashes {
|
||||
Some(RoomId::new(services.globals.server_name()))
|
||||
} else {
|
||||
Some(&RoomId::new(services.globals.server_name()))
|
||||
None
|
||||
};
|
||||
let replacement_room: Option<&RoomId> = replacement_room_owned.as_ref().map(AsRef::as_ref);
|
||||
let replacement_room_tmp = match replacement_room {
|
||||
| Some(v) => v,
|
||||
| None => &RoomId::new(services.globals.server_name()),
|
||||
|
||||
@@ -44,7 +44,7 @@ pub(crate) async fn get_hierarchy_route(
|
||||
.as_ref()
|
||||
.and_then(|s| PaginationToken::from_str(s).ok());
|
||||
|
||||
// Should prevent unexpeded behaviour in (bad) clients
|
||||
// Should prevent unexpected behaviour in (bad) clients
|
||||
if let Some(ref token) = key {
|
||||
if token.suggested_only != body.suggested_only || token.max_depth != max_depth {
|
||||
return Err!(Request(InvalidParam(
|
||||
|
||||
@@ -320,6 +320,7 @@ where
|
||||
|
||||
for mut range in ranges {
|
||||
range.0 = uint!(0);
|
||||
range.1 = range.1.checked_add(uint!(1)).unwrap_or(range.1);
|
||||
range.1 = range
|
||||
.1
|
||||
.clamp(range.0, UInt::try_from(active_rooms.len()).unwrap_or(UInt::MAX));
|
||||
|
||||
@@ -226,6 +226,7 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
|
||||
.ruma_route(&server::well_known_server)
|
||||
.ruma_route(&server::get_content_route)
|
||||
.ruma_route(&server::get_content_thumbnail_route)
|
||||
.ruma_route(&server::get_edutypes_route)
|
||||
.route("/_conduwuit/local_user_count", get(client::conduwuit_local_user_count))
|
||||
.route("/_continuwuity/local_user_count", get(client::conduwuit_local_user_count));
|
||||
} else {
|
||||
|
||||
@@ -34,6 +34,19 @@ pub(super) async fn from(
|
||||
|
||||
let max_body_size = services.server.config.max_request_size;
|
||||
|
||||
// Check if the Content-Length header is present and valid, saves us streaming
|
||||
// the response into memory
|
||||
if let Some(content_length) = parts.headers.get(http::header::CONTENT_LENGTH) {
|
||||
if let Ok(content_length) = content_length
|
||||
.to_str()
|
||||
.map(|s| s.parse::<usize>().unwrap_or_default())
|
||||
{
|
||||
if content_length > max_body_size {
|
||||
return Err(err!(Request(TooLarge("Request body too large"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let body = axum::body::to_bytes(body, max_body_size)
|
||||
.await
|
||||
.map_err(|e| err!(Request(TooLarge("Request body too large: {e}"))))?;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
use axum::extract::State;
|
||||
use conduwuit::Result;
|
||||
use ruma::api::federation::edutypes::get_edutypes;
|
||||
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `GET /_matrix/federation/v1/edutypes`
|
||||
///
|
||||
/// Lists EDU types we wish to receive
|
||||
pub(crate) async fn get_edutypes_route(
|
||||
State(services): State<crate::State>,
|
||||
_body: Ruma<get_edutypes::unstable::Request>,
|
||||
) -> Result<get_edutypes::unstable::Response> {
|
||||
Ok(get_edutypes::unstable::Response {
|
||||
typing: services.config.allow_incoming_typing,
|
||||
presence: services.config.allow_incoming_presence,
|
||||
receipt: services.config.allow_incoming_read_receipts,
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub(super) mod backfill;
|
||||
pub(super) mod edutypes;
|
||||
pub(super) mod event;
|
||||
pub(super) mod event_auth;
|
||||
pub(super) mod get_missing_events;
|
||||
@@ -23,6 +24,7 @@ pub(super) mod version;
|
||||
pub(super) mod well_known;
|
||||
|
||||
pub(super) use backfill::*;
|
||||
pub(super) use edutypes::*;
|
||||
pub(super) use event::*;
|
||||
pub(super) use event_auth::*;
|
||||
pub(super) use get_missing_events::*;
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ ruma.workspace = true
|
||||
sanitize-filename.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_regex.workspace = true
|
||||
serde_yml.workspace = true
|
||||
serde-saphyr.workspace = true
|
||||
serde.workspace = true
|
||||
smallvec.workspace = true
|
||||
smallstr.workspace = true
|
||||
|
||||
@@ -1128,6 +1128,23 @@ pub struct Config {
|
||||
#[serde(default = "true_fn")]
|
||||
pub rocksdb_bottommost_compression: bool,
|
||||
|
||||
/// Compression algorithm for RocksDB's Write-Ahead-Log (WAL).
|
||||
///
|
||||
/// At present, only ZSTD compression is supported by RocksDB for WAL
|
||||
/// compression. Enabling this can reduce WAL size at the expense of some
|
||||
/// CPU usage during writes.
|
||||
///
|
||||
/// The options are:
|
||||
/// - "none" = No compression
|
||||
/// - "zstd" = ZSTD compression
|
||||
///
|
||||
/// For more information on WAL compression, see:
|
||||
/// https://github.com/facebook/rocksdb/wiki/WAL-Compression
|
||||
///
|
||||
/// default: "zstd"
|
||||
#[serde(default = "default_rocksdb_wal_compression")]
|
||||
pub rocksdb_wal_compression: String,
|
||||
|
||||
/// Database recovery mode (for RocksDB WAL corruption).
|
||||
///
|
||||
/// Use this option when the server reports corruption and refuses to start.
|
||||
@@ -1710,6 +1727,19 @@ pub struct Config {
|
||||
#[serde(default)]
|
||||
pub block_non_admin_invites: bool,
|
||||
|
||||
/// Enable or disable making requests to MSC4284 Policy Servers.
|
||||
/// It is recommended you keep this enabled unless you experience frequent
|
||||
/// connectivity issues, such as in a restricted networking environment.
|
||||
#[serde(default = "true_fn")]
|
||||
pub enable_msc4284_policy_servers: bool,
|
||||
|
||||
/// Enable running locally generated events through configured MSC4284
|
||||
/// policy servers. You may wish to disable this if your server is
|
||||
/// single-user for a slight speed benefit in some rooms, but otherwise
|
||||
/// should leave it enabled.
|
||||
#[serde(default = "true_fn")]
|
||||
pub policy_server_check_own_events: bool,
|
||||
|
||||
/// Allow admins to enter commands in rooms other than "#admins" (admin
|
||||
/// room) by prefixing your message with "\!admin" or "\\!admin" followed up
|
||||
/// a normal continuwuity admin command. The reply will be publicly visible
|
||||
@@ -2441,6 +2471,8 @@ fn default_rocksdb_compression_algo() -> String {
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn default_rocksdb_wal_compression() -> String { "zstd".to_owned() }
|
||||
|
||||
/// Default RocksDB compression level is 32767, which is internally read by
|
||||
/// RocksDB as the default magic number and translated to the library's default
|
||||
/// compression level as they all differ. See their `kDefaultCompressionLevel`.
|
||||
|
||||
@@ -83,7 +83,9 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
TypedHeader(#[from] axum_extra::typed_header::TypedHeaderRejection),
|
||||
#[error(transparent)]
|
||||
Yaml(#[from] serde_yml::Error),
|
||||
YamlDe(#[from] serde_saphyr::Error),
|
||||
#[error(transparent)]
|
||||
YamlSer(#[from] serde_saphyr::ser_error::Error),
|
||||
|
||||
// ruma/conduwuit
|
||||
#[error("Arithmetic operation failed: {0}")]
|
||||
|
||||
@@ -5,13 +5,17 @@
|
||||
|
||||
use std::{collections::BTreeMap, sync::OnceLock};
|
||||
|
||||
use crate::{SyncMutex, utils::exchange};
|
||||
use crate::utils::exchange;
|
||||
|
||||
/// Raw capture of rustc flags used to build each crate in the project. Informed
|
||||
/// by rustc_flags_capture macro (one in each crate's mod.rs). This is
|
||||
/// done during static initialization which is why it's mutex-protected and pub.
|
||||
/// Should not be written to by anything other than our macro.
|
||||
pub static FLAGS: SyncMutex<BTreeMap<&str, &[&str]>> = SyncMutex::new(BTreeMap::new());
|
||||
///
|
||||
/// We specifically use a std mutex here because parking_lot cannot be used
|
||||
/// after thread local storage is destroyed on MacOS.
|
||||
pub static FLAGS: std::sync::Mutex<BTreeMap<&str, &[&str]>> =
|
||||
std::sync::Mutex::new(BTreeMap::new());
|
||||
|
||||
/// Processed list of enabled features across all project crates. This is
|
||||
/// generated from the data in FLAGS.
|
||||
@@ -24,6 +28,7 @@ fn init_features() -> Vec<&'static str> {
|
||||
let mut features = Vec::new();
|
||||
FLAGS
|
||||
.lock()
|
||||
.expect("locked")
|
||||
.iter()
|
||||
.for_each(|(_, flags)| append_features(&mut features, flags));
|
||||
|
||||
|
||||
@@ -101,40 +101,40 @@ where
|
||||
debug!(version = ?stateres_version, "State resolution starting");
|
||||
|
||||
// Split non-conflicting and conflicting state
|
||||
let (unconflicted, conflicting) = separate(state_sets.into_iter());
|
||||
let (clean, conflicting) = separate(state_sets.into_iter());
|
||||
|
||||
debug!(count = unconflicted.len(), "non-conflicting events");
|
||||
trace!(map = ?unconflicted, "non-conflicting events");
|
||||
debug!(count = clean.len(), "non-conflicting events");
|
||||
trace!(map = ?clean, "non-conflicting events");
|
||||
|
||||
if conflicting.is_empty() {
|
||||
debug!("no conflicting state found");
|
||||
return Ok(unconflicted);
|
||||
return Ok(clean);
|
||||
}
|
||||
|
||||
debug!(count = conflicting.len(), "conflicting events");
|
||||
trace!(map = ?conflicting, "conflicting events");
|
||||
let (conflicted_state_subgraph, initial_state) =
|
||||
if stateres_version == StateResolutionVersion::V2_1 {
|
||||
let csg = calculate_conflicted_subgraph(&conflicting, event_fetch)
|
||||
let conflicted_state_subgraph: HashSet<_> = match stateres_version {
|
||||
| StateResolutionVersion::V2_1 =>
|
||||
calculate_conflicted_subgraph(&conflicting, event_fetch)
|
||||
.await
|
||||
.ok_or_else(|| {
|
||||
Error::InvalidPdu("Failed to calculate conflicted subgraph".to_owned())
|
||||
})?;
|
||||
debug!(count = csg.len(), "conflicted subgraph");
|
||||
trace!(set = ?csg, "conflicted subgraph");
|
||||
(csg, HashMap::new())
|
||||
} else {
|
||||
(HashSet::new(), unconflicted.clone())
|
||||
};
|
||||
})?,
|
||||
| _ => HashSet::new(),
|
||||
};
|
||||
debug!(count = conflicted_state_subgraph.len(), "conflicted subgraph");
|
||||
trace!(set = ?conflicted_state_subgraph, "conflicted subgraph");
|
||||
|
||||
let conflicting_values = conflicting.into_values().flatten().stream();
|
||||
|
||||
// `all_conflicted` contains unique items
|
||||
// synapse says `full_set = {eid for eid in full_conflicted_set if eid in
|
||||
// event_map}`
|
||||
// Hydra: Also consider the conflicted state subgraph
|
||||
let all_conflicted: HashSet<_> = get_auth_chain_diff(auth_chain_sets)
|
||||
.chain(conflicting.into_values().flatten().stream())
|
||||
.broad_filter_map(async |id| event_exists(id.clone()).await.then_some(id))
|
||||
.chain(conflicting_values)
|
||||
.chain(conflicted_state_subgraph.into_iter().stream())
|
||||
.broad_filter_map(async |id| event_exists(id.clone()).await.then_some(id))
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
@@ -169,8 +169,9 @@ where
|
||||
// Sequentially auth check each control event.
|
||||
let resolved_control = iterative_auth_check(
|
||||
&room_version,
|
||||
&stateres_version,
|
||||
sorted_control_levels.iter().stream().map(AsRef::as_ref),
|
||||
initial_state,
|
||||
clean.clone(),
|
||||
&event_fetch,
|
||||
)
|
||||
.await?;
|
||||
@@ -200,7 +201,7 @@ where
|
||||
let power_levels_ty_sk = (StateEventType::RoomPowerLevels, StateKey::new());
|
||||
let power_event = resolved_control.get(&power_levels_ty_sk);
|
||||
|
||||
trace!(event_id = ?power_event, "power event");
|
||||
debug!(event_id = ?power_event, "power event");
|
||||
|
||||
let sorted_left_events =
|
||||
mainline_sort(&events_to_resolve, power_event.cloned(), &event_fetch).await?;
|
||||
@@ -209,14 +210,15 @@ where
|
||||
|
||||
let mut resolved_state = iterative_auth_check(
|
||||
&room_version,
|
||||
&stateres_version,
|
||||
sorted_left_events.iter().stream().map(AsRef::as_ref),
|
||||
resolved_control, // The control events are added to the final resolved state
|
||||
resolved_control.clone(), // The control events are added to the final resolved state
|
||||
&event_fetch,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Ensure unconflicting state is in the final state
|
||||
resolved_state.extend(unconflicted);
|
||||
resolved_state.extend(clean);
|
||||
|
||||
debug!("state resolution finished");
|
||||
trace!( map = ?resolved_state, "final resolved state" );
|
||||
@@ -595,6 +597,7 @@ where
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
async fn iterative_auth_check<'a, E, F, Fut, S>(
|
||||
room_version: &RoomVersion,
|
||||
stateres_version: &StateResolutionVersion,
|
||||
events_to_check: S,
|
||||
unconflicted_state: StateMap<OwnedEventId>,
|
||||
fetch_event: &F,
|
||||
@@ -619,10 +622,6 @@ where
|
||||
.boxed()
|
||||
.await?;
|
||||
trace!(list = ?events_to_check, "events to check");
|
||||
if events_to_check.is_empty() {
|
||||
debug!("no events to check, returning unconflicted state");
|
||||
return Ok(unconflicted_state);
|
||||
}
|
||||
|
||||
let auth_event_ids: HashSet<OwnedEventId> = events_to_check
|
||||
.iter()
|
||||
@@ -643,11 +642,10 @@ where
|
||||
trace!(map = ?auth_events.keys().collect::<Vec<_>>(), "fetched auth events");
|
||||
|
||||
let auth_events = &auth_events;
|
||||
// NOTE: in state resolution v2.1, auth checks should start with an empty state
|
||||
// map. It is the caller's job to do this. Previously, this function would
|
||||
// force an empty state map in this case, and this resulted in power events
|
||||
// going missing from the resolved state as they'd be discarded here.
|
||||
let mut resolved_state = unconflicted_state;
|
||||
let mut resolved_state = match stateres_version {
|
||||
| StateResolutionVersion::V2_1 => StateMap::new(),
|
||||
| _ => unconflicted_state,
|
||||
};
|
||||
for event in events_to_check {
|
||||
trace!(event_id = event.event_id().as_str(), "checking event");
|
||||
let state_key = event
|
||||
@@ -1035,6 +1033,7 @@ mod tests {
|
||||
|
||||
let resolved_power = super::iterative_auth_check(
|
||||
&RoomVersion::V6,
|
||||
&StateResolutionVersion::V2,
|
||||
sorted_power_events.iter().map(AsRef::as_ref).stream(),
|
||||
HashMap::new(), // unconflicted events
|
||||
&fetcher,
|
||||
|
||||
@@ -276,3 +276,22 @@ async fn set_intersection_sorted_stream2() {
|
||||
.await;
|
||||
assert!(r.eq(&["ccc", "ggg", "iii"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_within_bounds() {
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use utils::time::{TimeDirection, is_within_bounds};
|
||||
|
||||
let now = SystemTime::now();
|
||||
let yesterday = now - Duration::from_secs(86400);
|
||||
assert!(is_within_bounds(yesterday, now, TimeDirection::Before));
|
||||
assert!(!is_within_bounds(yesterday, now, TimeDirection::After));
|
||||
|
||||
let tomorrow = now + Duration::from_secs(86400);
|
||||
assert!(is_within_bounds(tomorrow, now, TimeDirection::After));
|
||||
assert!(!is_within_bounds(tomorrow, now, TimeDirection::Before));
|
||||
|
||||
assert!(is_within_bounds(now, now, TimeDirection::Before));
|
||||
assert!(is_within_bounds(now, now, TimeDirection::After));
|
||||
}
|
||||
|
||||
@@ -126,3 +126,24 @@ pub enum Unit {
|
||||
Micros(u128),
|
||||
Nanos(u128),
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
|
||||
pub enum TimeDirection {
|
||||
Before,
|
||||
After,
|
||||
}
|
||||
|
||||
/// Checks if `item_time` is before or after `time_boundary`.
|
||||
/// If both times are the same, it will return true for both directions, as the
|
||||
/// matching is inclusive.
|
||||
#[must_use]
|
||||
pub fn is_within_bounds(
|
||||
item_time: SystemTime,
|
||||
time_boundary: SystemTime,
|
||||
direction: TimeDirection,
|
||||
) -> bool {
|
||||
match direction {
|
||||
| TimeDirection::Before => item_time <= time_boundary,
|
||||
| TimeDirection::After => item_time >= time_boundary,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use std::{cmp, convert::TryFrom};
|
||||
|
||||
use conduwuit::{Config, Result, utils};
|
||||
use rocksdb::{Cache, DBRecoveryMode, Env, LogLevel, Options, statistics::StatsLevel};
|
||||
use conduwuit::{Config, Result, utils, warn};
|
||||
use rocksdb::{
|
||||
Cache, DBCompressionType, DBRecoveryMode, Env, LogLevel, Options, statistics::StatsLevel,
|
||||
};
|
||||
|
||||
use super::{cf_opts::cache_size_f64, logger::handle as handle_log};
|
||||
|
||||
@@ -58,6 +60,20 @@ pub(crate) fn db_options(config: &Config, env: &Env, row_cache: &Cache) -> Resul
|
||||
opts.set_max_total_wal_size(1024 * 1024 * 512);
|
||||
opts.set_writable_file_max_buffer_size(1024 * 1024 * 2);
|
||||
|
||||
// WAL compression
|
||||
let wal_compression = match config.rocksdb_wal_compression.as_ref() {
|
||||
| "zstd" => DBCompressionType::Zstd,
|
||||
| "none" => DBCompressionType::None,
|
||||
| value => {
|
||||
warn!(
|
||||
"Invalid rocksdb_wal_compression value '{value}'. Supported values are 'none' \
|
||||
or 'zstd'. Defaulting to 'none'."
|
||||
);
|
||||
DBCompressionType::None
|
||||
},
|
||||
};
|
||||
opts.set_wal_compression_type(wal_compression);
|
||||
|
||||
// Misc
|
||||
opts.set_disable_auto_compactions(!config.rocksdb_compaction);
|
||||
opts.create_missing_column_families(true);
|
||||
|
||||
+2
-2
@@ -15,13 +15,13 @@ pub(super) fn flags_capture(args: TokenStream) -> TokenStream {
|
||||
|
||||
#[ctor]
|
||||
fn _set_rustc_flags() {
|
||||
conduwuit_core::info::rustc::FLAGS.lock().insert(#crate_name, &RUSTC_FLAGS);
|
||||
conduwuit_core::info::rustc::FLAGS.lock().expect("locked").insert(#crate_name, &RUSTC_FLAGS);
|
||||
}
|
||||
|
||||
// static strings have to be yanked on module unload
|
||||
#[dtor]
|
||||
fn _unset_rustc_flags() {
|
||||
conduwuit_core::info::rustc::FLAGS.lock().remove(#crate_name);
|
||||
conduwuit_core::info::rustc::FLAGS.lock().expect("locked").remove(#crate_name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+9
-7
@@ -22,11 +22,13 @@ crate-type = [
|
||||
]
|
||||
|
||||
[package.metadata.deb]
|
||||
name = "conduwuit"
|
||||
maintainer = "strawberry <strawberry@puppygock.gay>"
|
||||
copyright = "2024, strawberry <strawberry@puppygock.gay>"
|
||||
name = "continuwuity"
|
||||
maintainer = "continuwuity developers <contact@continuwuity.org>"
|
||||
copyright = "2024, continuwuity developers"
|
||||
license-file = ["../../LICENSE", "3"]
|
||||
depends = "$auto, ca-certificates"
|
||||
breaks = ["conduwuit (<<0.5.0)"]
|
||||
replaces = ["conduwuit (<<0.5.0)"]
|
||||
extended-description = """\
|
||||
a cool hard fork of Conduit, a Matrix homeserver written in Rust"""
|
||||
section = "net"
|
||||
@@ -60,7 +62,8 @@ standard = [
|
||||
"media_thumbnail",
|
||||
"systemd",
|
||||
"url_preview",
|
||||
"zstd_compression"
|
||||
"zstd_compression",
|
||||
"sentry_telemetry"
|
||||
]
|
||||
full = [
|
||||
"standard",
|
||||
@@ -127,7 +130,6 @@ perf_measurements = [
|
||||
"dep:tracing-opentelemetry",
|
||||
"dep:opentelemetry_sdk",
|
||||
"dep:opentelemetry-otlp",
|
||||
"dep:opentelemetry-jaeger-propagator",
|
||||
"conduwuit-core/perf_measurements",
|
||||
"conduwuit-core/sentry_telemetry",
|
||||
]
|
||||
@@ -154,6 +156,7 @@ sentry_telemetry = [
|
||||
]
|
||||
systemd = [
|
||||
"conduwuit-router/systemd",
|
||||
"conduwuit-service/systemd"
|
||||
]
|
||||
journald = [ # This is a stub on non-unix platforms
|
||||
"dep:tracing-journald",
|
||||
@@ -198,6 +201,7 @@ conduwuit-core.workspace = true
|
||||
conduwuit-database.workspace = true
|
||||
conduwuit-router.workspace = true
|
||||
conduwuit-service.workspace = true
|
||||
conduwuit-build-metadata.workspace = true
|
||||
|
||||
clap.workspace = true
|
||||
console-subscriber.optional = true
|
||||
@@ -209,8 +213,6 @@ opentelemetry.optional = true
|
||||
opentelemetry.workspace = true
|
||||
opentelemetry-otlp.optional = true
|
||||
opentelemetry-otlp.workspace = true
|
||||
opentelemetry-jaeger-propagator.optional = true
|
||||
opentelemetry-jaeger-propagator.workspace = true
|
||||
opentelemetry_sdk.optional = true
|
||||
opentelemetry_sdk.workspace = true
|
||||
sentry-tower.optional = true
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ pub(crate) fn init(
|
||||
|
||||
let otlp_layer = config.allow_otlp.then(|| {
|
||||
opentelemetry::global::set_text_map_propagator(
|
||||
opentelemetry_jaeger_propagator::Propagator::new(),
|
||||
opentelemetry_sdk::propagation::TraceContextPropagator::new(),
|
||||
);
|
||||
|
||||
let exporter = opentelemetry_otlp::SpanExporter::builder()
|
||||
|
||||
+21
-1
@@ -1,10 +1,12 @@
|
||||
#![cfg(feature = "sentry_telemetry")]
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
str::FromStr,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
|
||||
use conduwuit_build_metadata as build;
|
||||
use conduwuit_core::{config::Config, debug, trace};
|
||||
use sentry::{
|
||||
Breadcrumb, ClientOptions, Level,
|
||||
@@ -44,7 +46,7 @@ fn options(config: &Config) -> ClientOptions {
|
||||
server_name,
|
||||
traces_sample_rate: config.sentry_traces_sample_rate,
|
||||
debug: cfg!(debug_assertions),
|
||||
release: sentry::release_name!(),
|
||||
release: release_name(),
|
||||
user_agent: conduwuit_core::version::user_agent().into(),
|
||||
attach_stacktrace: config.sentry_attach_stacktrace,
|
||||
before_send: Some(Arc::new(before_send)),
|
||||
@@ -91,3 +93,21 @@ fn before_breadcrumb(crumb: Breadcrumb) -> Option<Breadcrumb> {
|
||||
trace!("Sentry breadcrumb: {crumb:?}");
|
||||
Some(crumb)
|
||||
}
|
||||
|
||||
fn release_name() -> Option<Cow<'static, str>> {
|
||||
static RELEASE: OnceLock<Option<String>> = OnceLock::new();
|
||||
|
||||
RELEASE
|
||||
.get_or_init(|| {
|
||||
let pkg_name = env!("CARGO_PKG_NAME");
|
||||
let pkg_version = env!("CARGO_PKG_VERSION");
|
||||
|
||||
if let Some(commit_short) = build::GIT_COMMIT_HASH_SHORT {
|
||||
Some(format!("{pkg_name}@{pkg_version}+{commit_short}"))
|
||||
} else {
|
||||
Some(format!("{pkg_name}@{pkg_version}"))
|
||||
}
|
||||
})
|
||||
.as_ref()
|
||||
.map(|s| Cow::Borrowed(s.as_str()))
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ io_uring = [
|
||||
"conduwuit-admin/io_uring",
|
||||
"conduwuit-api/io_uring",
|
||||
"conduwuit-service/io_uring",
|
||||
"conduwuit-api/io_uring",
|
||||
]
|
||||
jemalloc = [
|
||||
"conduwuit-admin/jemalloc",
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ pub(crate) async fn start(server: Arc<Server>) -> Result<Arc<Services>> {
|
||||
let services = Services::build(server).await?.start().await?;
|
||||
|
||||
#[cfg(all(feature = "systemd", target_os = "linux"))]
|
||||
sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
|
||||
sd_notify::notify(false, &[sd_notify::NotifyState::Ready])
|
||||
.expect("failed to notify systemd of ready state");
|
||||
|
||||
debug!("Started");
|
||||
@@ -78,7 +78,7 @@ pub(crate) async fn stop(services: Arc<Services>) -> Result<()> {
|
||||
debug!("Shutting down...");
|
||||
|
||||
#[cfg(all(feature = "systemd", target_os = "linux"))]
|
||||
sd_notify::notify(true, &[sd_notify::NotifyState::Stopping])
|
||||
sd_notify::notify(false, &[sd_notify::NotifyState::Stopping])
|
||||
.expect("failed to notify systemd of stopping state");
|
||||
|
||||
// Wait for all completions before dropping or we'll lose them to the module
|
||||
|
||||
@@ -67,6 +67,9 @@ release_max_log_level = [
|
||||
"tracing/max_level_trace",
|
||||
"tracing/release_max_level_info",
|
||||
]
|
||||
systemd = [
|
||||
"dep:sd-notify",
|
||||
]
|
||||
url_preview = [
|
||||
"dep:image",
|
||||
"dep:webpage",
|
||||
@@ -105,7 +108,7 @@ rustyline-async.workspace = true
|
||||
rustyline-async.optional = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
serde_yml.workspace = true
|
||||
serde-saphyr.workspace = true
|
||||
sha2.workspace = true
|
||||
termimad.workspace = true
|
||||
termimad.optional = true
|
||||
@@ -119,5 +122,9 @@ blurhash.optional = true
|
||||
recaptcha-verify = { version = "0.1.5", default-features = false }
|
||||
ctor.workspace = true
|
||||
|
||||
[target.'cfg(all(unix, target_os = "linux"))'.dependencies]
|
||||
sd-notify.workspace = true
|
||||
sd-notify.optional = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -271,7 +271,7 @@ impl Service {
|
||||
.id_appserviceregistrations
|
||||
.get(id)
|
||||
.await
|
||||
.and_then(|ref bytes| serde_yml::from_slice(bytes).map_err(Into::into))
|
||||
.and_then(|ref bytes| serde_saphyr::from_slice(bytes).map_err(Into::into))
|
||||
.map_err(|e| err!(Database("Invalid appservice {id:?} registration: {e:?}")))
|
||||
}
|
||||
|
||||
|
||||
@@ -45,13 +45,16 @@ impl Deref for Service {
|
||||
fn handle_reload(&self) -> Result {
|
||||
if self.server.config.config_reload_signal {
|
||||
#[cfg(all(feature = "systemd", target_os = "linux"))]
|
||||
sd_notify::notify(true, &[sd_notify::NotifyState::Reloading])
|
||||
.expect("failed to notify systemd of reloading state");
|
||||
sd_notify::notify(false, &[
|
||||
sd_notify::NotifyState::Reloading,
|
||||
sd_notify::NotifyState::monotonic_usec_now().expect("Failed to read monotonic time"),
|
||||
])
|
||||
.expect("failed to notify systemd of reloading state");
|
||||
|
||||
self.reload(iter::empty())?;
|
||||
|
||||
#[cfg(all(feature = "systemd", target_os = "linux"))]
|
||||
sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
|
||||
sd_notify::notify(false, &[sd_notify::NotifyState::Ready])
|
||||
.expect("failed to notify systemd of ready state");
|
||||
}
|
||||
|
||||
|
||||
+29
-26
@@ -11,7 +11,10 @@ use async_trait::async_trait;
|
||||
use base64::{Engine as _, engine::general_purpose};
|
||||
use conduwuit::{
|
||||
Err, Result, Server, debug, debug_error, debug_info, debug_warn, err, error, trace,
|
||||
utils::{self, MutexMap},
|
||||
utils::{
|
||||
self, MutexMap,
|
||||
time::{self, TimeDirection},
|
||||
},
|
||||
warn,
|
||||
};
|
||||
use ruma::{Mxc, OwnedMxcUri, UserId, http_headers::ContentDisposition};
|
||||
@@ -90,17 +93,22 @@ impl Service {
|
||||
file: &[u8],
|
||||
) -> Result<()> {
|
||||
// Width, Height = 0 if it's not a thumbnail
|
||||
let key = self.db.create_file_metadata(
|
||||
mxc,
|
||||
user,
|
||||
&Dim::default(),
|
||||
content_disposition,
|
||||
content_type,
|
||||
)?;
|
||||
let key = self
|
||||
.db
|
||||
.create_file_metadata(mxc, user, &Dim::default(), content_disposition, content_type)
|
||||
.map_err(|e| {
|
||||
err!(Database(error!("Failed to create media metadata for MXC {mxc}: {e}")))
|
||||
})?;
|
||||
|
||||
//TODO: Dangling metadata in database if creation fails
|
||||
let mut f = self.create_media_file(&key).await?;
|
||||
f.write_all(file).await?;
|
||||
let mut f = self.create_media_file(&key).await.map_err(|e| {
|
||||
err!(Database(error!(
|
||||
"Failed to create media file for MXC {mxc} at key {key:?}: {e}"
|
||||
)))
|
||||
})?;
|
||||
f.write_all(file).await.map_err(|e| {
|
||||
err!(Database(error!("Failed to write media file for MXC {mxc} at key {key:?}: {e}")))
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -221,13 +229,12 @@ impl Service {
|
||||
Ok(mxcs)
|
||||
}
|
||||
|
||||
/// Deletes all remote only media files in the given at or after
|
||||
/// time/duration. Returns a usize with the amount of media files deleted.
|
||||
pub async fn delete_all_remote_media_at_after_time(
|
||||
/// Deletes all media files in the given time frame.
|
||||
/// Returns a usize with the amount of media files deleted.
|
||||
pub async fn delete_all_media_within_timeframe(
|
||||
&self,
|
||||
time: SystemTime,
|
||||
before: bool,
|
||||
after: bool,
|
||||
time_boundary: SystemTime,
|
||||
direction: TimeDirection,
|
||||
yes_i_want_to_delete_local_media: bool,
|
||||
) -> Result<usize> {
|
||||
let all_keys = self.db.get_all_media_keys().await;
|
||||
@@ -294,18 +301,14 @@ impl Service {
|
||||
|
||||
debug!("File created at: {file_created_at:?}");
|
||||
|
||||
if file_created_at >= time && before {
|
||||
if time::is_within_bounds(file_created_at, time_boundary, direction) {
|
||||
debug!(
|
||||
"File is within (before) user duration, pushing to list of file paths and \
|
||||
keys to delete."
|
||||
);
|
||||
remote_mxcs.push(mxc.to_string());
|
||||
} else if file_created_at <= time && after {
|
||||
debug!(
|
||||
"File is not within (after) user duration, pushing to list of file paths \
|
||||
and keys to delete."
|
||||
"File is within bounds ({direction:?} {time_boundary:?}), pushing to list \
|
||||
of file paths and keys to delete.",
|
||||
);
|
||||
remote_mxcs.push(mxc.to_string());
|
||||
} else {
|
||||
debug!("File is outside bounds ({direction:?} {time_boundary:?}), ignoring.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +316,7 @@ impl Service {
|
||||
return Err!(Database("Did not found any eligible MXCs to delete."));
|
||||
}
|
||||
|
||||
debug_info!("Deleting media now in the past {time:?}");
|
||||
debug_info!("Deleting media now {direction:?} {time_boundary:?}");
|
||||
|
||||
let mut deletion_count: usize = 0;
|
||||
|
||||
|
||||
@@ -31,6 +31,19 @@ pub async fn ask_policy_server(
|
||||
pdu_json: &CanonicalJsonObject,
|
||||
room_id: &RoomId,
|
||||
) -> Result<bool> {
|
||||
if !self.services.server.config.enable_msc4284_policy_servers {
|
||||
return Ok(true); // don't ever contact policy servers
|
||||
}
|
||||
if self.services.server.config.policy_server_check_own_events
|
||||
&& pdu.origin.is_some()
|
||||
&& self
|
||||
.services
|
||||
.server
|
||||
.is_ours(pdu.origin.as_ref().unwrap().as_str())
|
||||
{
|
||||
return Ok(true); // don't contact policy servers for locally generated events
|
||||
}
|
||||
|
||||
if *pdu.event_type() == StateEventType::RoomPolicy.into() {
|
||||
debug!(
|
||||
room_id = %room_id,
|
||||
|
||||
@@ -267,9 +267,9 @@ pub async fn create_hash_and_sign_event(
|
||||
| _ => Err!(Request(Unknown(warn!("Signing event failed: {e}")))),
|
||||
};
|
||||
}
|
||||
// Check with the policy server
|
||||
// Generate event id
|
||||
pdu.event_id = gen_event_id(&pdu_json, &room_version_id)?;
|
||||
// Check with the policy server
|
||||
pdu_json.insert("event_id".into(), CanonicalJsonValue::String(pdu.event_id.clone().into()));
|
||||
if room_id.is_some() {
|
||||
trace!(
|
||||
@@ -295,32 +295,6 @@ pub async fn create_hash_and_sign_event(
|
||||
}
|
||||
}
|
||||
|
||||
// Check with the policy server
|
||||
if room_id.is_some() {
|
||||
trace!(
|
||||
"Checking event {} in room {} with policy server",
|
||||
pdu.event_id,
|
||||
pdu.room_id.as_ref().map_or("None", |id| id.as_str())
|
||||
);
|
||||
match self
|
||||
.services
|
||||
.event_handler
|
||||
.ask_policy_server(&pdu, &pdu_json, &pdu.room_id_or_hash())
|
||||
.await
|
||||
{
|
||||
| Ok(true) => {},
|
||||
| Ok(false) => {
|
||||
return Err!(Request(Forbidden(debug_warn!(
|
||||
"Policy server marked this event as spam"
|
||||
))));
|
||||
},
|
||||
| Err(e) => {
|
||||
// fail open
|
||||
warn!("Failed to check event with policy server: {e}");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Generate short event id
|
||||
trace!(
|
||||
"Generating short event ID for {} in room {}",
|
||||
|
||||
@@ -345,7 +345,7 @@ impl Service {
|
||||
}
|
||||
|
||||
/// Sets a new displayname or removes it if displayname is None. You still
|
||||
/// need to nofify all rooms of this change.
|
||||
/// need to notify all rooms of this change.
|
||||
pub fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) {
|
||||
if let Some(displayname) = displayname {
|
||||
self.db.userid_displayname.insert(user_id, displayname);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[formatting]
|
||||
align_entries = true # Align entries vertically. Entries that have table headers, comments, or blank lines between them are not aligned.
|
||||
|
||||
reorder_arrays = true # Alphabetically reorder array values that are not separated by blank lines.
|
||||
reorder_inline_tables = true # Alphabetically reorder inline tables.
|
||||
reorder_keys = true # Alphabetically reorder keys that are not separated by blank lines.
|
||||
Reference in New Issue
Block a user